From 3319655e2b5a2fcc680acc3e346cc7d782643990 Mon Sep 17 00:00:00 2001 From: TectonicEd Date: Tue, 25 Feb 2014 23:52:33 +0000 Subject: [PATCH 01/34] Clarifying error message This error will be triggered if either setting the group or the user is the problem. Fixing the wording after being led astray tracking down issue that was group, not user, related. --- src/NzbDrone.Mono/DiskProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Mono/DiskProvider.cs b/src/NzbDrone.Mono/DiskProvider.cs index cfbaa98c4..877f5c129 100644 --- a/src/NzbDrone.Mono/DiskProvider.cs +++ b/src/NzbDrone.Mono/DiskProvider.cs @@ -99,7 +99,7 @@ namespace NzbDrone.Mono { var error = Stdlib.GetLastError(); - throw new LinuxPermissionsException("Error setting file owner: " + error); + throw new LinuxPermissionsException("Error setting file owner and/or group: " + error); } } From a467c2346f6a843459c61cf4ade225fd967dfc9b Mon Sep 17 00:00:00 2001 From: TectonicEd Date: Wed, 26 Feb 2014 09:13:30 +0000 Subject: [PATCH 02/34] Bug fix: get groupname of group rather than user --- src/NzbDrone.Mono/DiskProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Mono/DiskProvider.cs b/src/NzbDrone.Mono/DiskProvider.cs index cfbaa98c4..da219f698 100644 --- a/src/NzbDrone.Mono/DiskProvider.cs +++ b/src/NzbDrone.Mono/DiskProvider.cs @@ -85,7 +85,7 @@ namespace NzbDrone.Mono if (!uint.TryParse(group, out groupId)) { - var g = Syscall.getgrnam(user); + var g = Syscall.getgrnam(group); if (g == null) { From d0d5a3d3b18415eef78bebb14adc0faa4229fd5b Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 8 Mar 2014 08:47:38 -0800 Subject: [PATCH 03/34] Series collection will page to 100000 instead of 1000 --- src/UI/Series/SeriesCollection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UI/Series/SeriesCollection.js b/src/UI/Series/SeriesCollection.js index 4f00e6c42..8bc23630e 100644 --- a/src/UI/Series/SeriesCollection.js +++ b/src/UI/Series/SeriesCollection.js @@ -18,7 +18,7 @@ define( state: { sortKey: 'title', order : -1, - pageSize: 1000 + pageSize: 100000 }, mode: 'client', From 9d74693bb7621fc2bbc942ca59f8a421fbdd1bf4 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 8 Mar 2014 10:35:48 -0800 Subject: [PATCH 04/34] Added Series Scanned Event --- .../MediaFiles/DiskScanService.cs | 18 ++++++++++++------ .../MediaFiles/Events/SeriesScannedEvent.cs | 15 +++++++++++++++ src/NzbDrone.Core/NzbDrone.Core.csproj | 1 + 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 0b1e51be6..79d53a9a8 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -8,6 +8,7 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.MediaFiles.Commands; using NzbDrone.Core.MediaFiles.EpisodeImport; +using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Tv; @@ -31,15 +32,17 @@ namespace NzbDrone.Core.MediaFiles private readonly ICommandExecutor _commandExecutor; private readonly IConfigService _configService; private readonly ISeriesService _seriesService; + private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; public DiskScanService(IDiskProvider diskProvider, - IMakeImportDecision importDecisionMaker, - IImportApprovedEpisodes importApprovedEpisodes, - ICommandExecutor commandExecutor, - IConfigService configService, - ISeriesService seriesService, - Logger logger) + IMakeImportDecision importDecisionMaker, + IImportApprovedEpisodes importApprovedEpisodes, + ICommandExecutor commandExecutor, + IConfigService configService, + ISeriesService seriesService, + IEventAggregator eventAggregator, + Logger logger) { _diskProvider = diskProvider; _importDecisionMaker = importDecisionMaker; @@ -47,6 +50,7 @@ namespace NzbDrone.Core.MediaFiles _commandExecutor = commandExecutor; _configService = configService; _seriesService = seriesService; + _eventAggregator = eventAggregator; _logger = logger; } @@ -75,7 +79,9 @@ namespace NzbDrone.Core.MediaFiles var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series, false); _importApprovedEpisodes.Import(decisions); + _logger.Info("Completed scanning disk for {0}", series.Title); + _eventAggregator.PublishEvent(new SeriesScannedEvent(series)); } public string[] GetVideoFiles(string path, bool allDirectories = true) diff --git a/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs new file mode 100644 index 000000000..f82de5214 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs @@ -0,0 +1,15 @@ +using NzbDrone.Common.Messaging; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.MediaFiles.Events +{ + public class SeriesScannedEvent : IEvent + { + public Series Series { get; private set; } + + public SeriesScannedEvent(Series series) + { + Series = series; + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 166fee736..640fef368 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -317,6 +317,7 @@ + From d9eab040297d41b38f744bd75f2439807cdd6a9a Mon Sep 17 00:00:00 2001 From: JackDandy Date: Sat, 8 Mar 2014 19:01:51 +0000 Subject: [PATCH 05/34] Add new feature, set file date to episode aired date. Fix, use alternative Trakt API field for episode air time. Improve the Preview Rename tip. Add, new setting "Set File Date to Airdate" on the Media Management tab of the Settings page to toggle this feature for new, imported and auto updating media files. Change, home page "Series Editor" - "Rename" button to "Update Files" and add "Set File Date To Air Date" action button to this modal to add capability of updating legacy media. Add, non UTC functions given that Windows undesirably adds time to file times set when using UTC. Fix, the Trakt API response show.air_time_utc contains erroneous data, this is replaced with show.air_time. --- .../Config/MediaManagementConfigResource.cs | 1 + src/NzbDrone.Api/Logs/LogFileModule.cs | 2 +- src/NzbDrone.Common/Disk/DiskProviderBase.cs | 36 +++- src/NzbDrone.Common/Disk/IDiskProvider.cs | 3 + .../MediaCoverServiceFixture.cs | 2 +- .../NotUnpackingSpecificationFixture.cs | 2 +- .../RecycleBinProviderTests/CleanupFixture.cs | 4 +- .../Configuration/ConfigService.cs | 6 + .../Configuration/IConfigService.cs | 1 + .../MediaCover/MediaCoverService.cs | 2 +- .../Commands/AirDateSeriesCommand.cs | 18 ++ .../MediaFiles/EpisodeFileMovingService.cs | 8 + .../NotUnpackingSpecification.cs | 2 +- .../MediaFiles/Events/SeriesAirDatedEvent.cs | 15 ++ .../MediaFiles/RecycleBinProvider.cs | 2 +- .../MediaFiles/UpdateEpisodeFileService.cs | 156 ++++++++++++++++++ .../MetadataSource/TraktProxy.cs | 2 +- src/NzbDrone.Core/NzbDrone.Core.csproj | 3 + .../Series/Editor/SeriesEditorFooterView.js | 34 ++-- .../SeriesEditorFooterViewTemplate.html | 2 +- .../UpdateFilesSeriesView.js} | 19 ++- .../UpdateFilesSeriesViewTemplate.html} | 11 +- src/UI/Series/series.less | 6 +- .../FileManagementViewTemplate.html | 17 ++ 24 files changed, 316 insertions(+), 38 deletions(-) create mode 100644 src/NzbDrone.Core/MediaFiles/Commands/AirDateSeriesCommand.cs create mode 100644 src/NzbDrone.Core/MediaFiles/Events/SeriesAirDatedEvent.cs create mode 100644 src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs rename src/UI/Series/Editor/{Rename/RenameSeriesView.js => UpdateFiles/UpdateFilesSeriesView.js} (58%) rename src/UI/Series/Editor/{Rename/RenameSeriesViewTemplate.html => UpdateFiles/UpdateFilesSeriesViewTemplate.html} (56%) diff --git a/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs b/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs index 9ff4efc66..279955620 100644 --- a/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs +++ b/src/NzbDrone.Api/Config/MediaManagementConfigResource.cs @@ -6,6 +6,7 @@ namespace NzbDrone.Api.Config public class MediaManagementConfigResource : RestResource { public Boolean AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; } + public Boolean FileDateAiredDate { get; set; } public String RecycleBin { get; set; } public Boolean AutoDownloadPropers { get; set; } public Boolean CreateEmptySeriesFolders { get; set; } diff --git a/src/NzbDrone.Api/Logs/LogFileModule.cs b/src/NzbDrone.Api/Logs/LogFileModule.cs index b896e6020..544866a1d 100644 --- a/src/NzbDrone.Api/Logs/LogFileModule.cs +++ b/src/NzbDrone.Api/Logs/LogFileModule.cs @@ -35,7 +35,7 @@ namespace NzbDrone.Api.Logs { Id = i + 1, Filename = Path.GetFileName(file), - LastWriteTime = _diskProvider.GetLastFileWrite(file) + LastWriteTime = _diskProvider.GetLastFileWriteUTC(file) }); } diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index d4a21b3c4..42aadc7c9 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -77,6 +77,20 @@ namespace NzbDrone.Common.Disk } public DateTime GetLastFileWrite(string path) + { + PathEnsureFileExists(path); + + return new FileInfo(path).LastWriteTime; + } + + public DateTime GetLastFileWriteUTC(string path) + { + PathEnsureFileExists(path); + + return new FileInfo(path).LastWriteTimeUtc; + } + + private void PathEnsureFileExists(string path) { Ensure.That(path, () => path).IsValidPath(); @@ -84,8 +98,6 @@ namespace NzbDrone.Common.Disk { throw new FileNotFoundException("File doesn't exist: " + path); } - - return new FileInfo(path).LastWriteTimeUtc; } public void EnsureFolder(string path) @@ -305,6 +317,26 @@ namespace NzbDrone.Common.Disk Directory.SetLastWriteTimeUtc(path, dateTime); } + public void FileSetLastWriteTime(string path, DateTime dateTime) + { + Ensure.That(path, () => path).IsValidPath(); + + File.SetLastWriteTime(path, dateTime); + } + public void FileSetLastAccessTime(string path, DateTime dateTime) + { + Ensure.That(path, () => path).IsValidPath(); + + File.SetLastAccessTimeUtc(path, dateTime); + } + + public void FileSetLastAccessTimeUtc(string path, DateTime dateTime) + { + Ensure.That(path, () => path).IsValidPath(); + + File.SetLastAccessTimeUtc(path, dateTime); + } + public bool IsFileLocked(string file) { try diff --git a/src/NzbDrone.Common/Disk/IDiskProvider.cs b/src/NzbDrone.Common/Disk/IDiskProvider.cs index 5eac1610d..fa7abc2b0 100644 --- a/src/NzbDrone.Common/Disk/IDiskProvider.cs +++ b/src/NzbDrone.Common/Disk/IDiskProvider.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Common.Disk DateTime GetLastFolderWrite(string path); DateTime GetLastFileWrite(string path); + DateTime GetLastFileWriteUTC(string path); void EnsureFolder(string path); bool FolderExists(string path); bool FileExists(string path); @@ -33,6 +34,8 @@ namespace NzbDrone.Common.Disk void WriteAllText(string filename, string contents); void FileSetLastWriteTimeUtc(string path, DateTime dateTime); void FolderSetLastWriteTimeUtc(string path, DateTime dateTime); + void FileSetLastWriteTime(string path, DateTime dateTime); + void FileSetLastAccessTime(string path, DateTime dateTime); bool IsFileLocked(string path); string GetPathRoot(string path); string GetParentFolder(string path); diff --git a/src/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs b/src/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs index f06a50f77..ad3d58fa7 100644 --- a/src/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MediaCoverTests/MediaCoverServiceFixture.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests new MediaCover.MediaCover {CoverType = MediaCoverTypes.Banner} }; - Mocker.GetMock().Setup(c => c.GetLastFileWrite(It.IsAny())) + Mocker.GetMock().Setup(c => c.GetLastFileWriteUTC(It.IsAny())) .Returns(new DateTime(1234)); Mocker.GetMock().Setup(c => c.FileExists(It.IsAny())) diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs index ba39c485e..275f52601 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs @@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications private void GivenLastWriteTimeUtc(DateTime time) { Mocker.GetMock() - .Setup(s => s.GetLastFileWrite(It.IsAny())) + .Setup(s => s.GetLastFileWriteUTC(It.IsAny())) .Returns(time); } diff --git a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs index ba42b585a..32b673728 100644 --- a/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs +++ b/src/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests Mocker.GetMock().Setup(s => s.GetLastFolderWrite(It.IsAny())) .Returns(DateTime.UtcNow.AddDays(-10)); - Mocker.GetMock().Setup(s => s.GetLastFileWrite(It.IsAny())) + Mocker.GetMock().Setup(s => s.GetLastFileWriteUTC(It.IsAny())) .Returns(DateTime.UtcNow.AddDays(-10)); } @@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests Mocker.GetMock().Setup(s => s.GetLastFolderWrite(It.IsAny())) .Returns(DateTime.UtcNow.AddDays(-3)); - Mocker.GetMock().Setup(s => s.GetLastFileWrite(It.IsAny())) + Mocker.GetMock().Setup(s => s.GetLastFileWriteUTC(It.IsAny())) .Returns(DateTime.UtcNow.AddDays(-3)); } diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index a0aa00bc8..6a39a8191 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -86,6 +86,12 @@ namespace NzbDrone.Core.Configuration set { SetValue("AutoUnmonitorPreviouslyDownloadedEpisodes", value); } } + public bool FileDateAiredDate + { + get { return GetValueBoolean("FileDateAiredDate"); } + set { SetValue("FileDateAiredDate", value); } + } + public int Retention { get { return GetValueInt("Retention", 0); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index ca44cc046..22993f8be 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -20,6 +20,7 @@ namespace NzbDrone.Core.Configuration //Media Management Boolean AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; } + Boolean FileDateAiredDate { get; set; } String RecycleBin { get; set; } Boolean AutoDownloadPropers { get; set; } Boolean CreateEmptySeriesFolders { get; set; } diff --git a/src/NzbDrone.Core/MediaCover/MediaCoverService.cs b/src/NzbDrone.Core/MediaCover/MediaCoverService.cs index a208f28bd..540d99a76 100644 --- a/src/NzbDrone.Core/MediaCover/MediaCoverService.cs +++ b/src/NzbDrone.Core/MediaCover/MediaCoverService.cs @@ -67,7 +67,7 @@ namespace NzbDrone.Core.MediaCover if (_diskProvider.FileExists(filePath)) { - var lastWrite = _diskProvider.GetLastFileWrite(filePath); + var lastWrite = _diskProvider.GetLastFileWriteUTC(filePath); mediaCover.Url += "?lastWrite=" + lastWrite.Ticks; } } diff --git a/src/NzbDrone.Core/MediaFiles/Commands/AirDateSeriesCommand.cs b/src/NzbDrone.Core/MediaFiles/Commands/AirDateSeriesCommand.cs new file mode 100644 index 000000000..ed1fd5f81 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/Commands/AirDateSeriesCommand.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.MediaFiles.Commands +{ + public class AirDateSeriesCommand : Command + { + public List SeriesIds { get; set; } + + public override bool SendUpdatesToClient + { + get + { + return true; + } + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs index 904fbb29e..df8e3e9f3 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs @@ -22,18 +22,21 @@ namespace NzbDrone.Core.MediaFiles public class EpisodeFileMovingService : IMoveEpisodeFiles { private readonly IEpisodeService _episodeService; + private readonly IUpdateEpisodeFileService _updateEpisodeFileService; private readonly IBuildFileNames _buildFileNames; private readonly IDiskProvider _diskProvider; private readonly IConfigService _configService; private readonly Logger _logger; public EpisodeFileMovingService(IEpisodeService episodeService, + IUpdateEpisodeFileService updateEpisodeFileService, IBuildFileNames buildFileNames, IDiskProvider diskProvider, IConfigService configService, Logger logger) { _episodeService = episodeService; + _updateEpisodeFileService = updateEpisodeFileService; _buildFileNames = buildFileNames; _diskProvider = diskProvider; _configService = configService; @@ -102,6 +105,11 @@ namespace NzbDrone.Core.MediaFiles _diskProvider.MoveFile(episodeFile.Path, destinationFilename); episodeFile.Path = destinationFilename; + if (_configService.FileDateAiredDate) + { + _updateEpisodeFileService.ChangeFileDateToAirdate(episodeFile, series); + } + try { _logger.Trace("Setting last write time on series folder: {0}", series.Path); diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs index 50279a4e2..4edad3102 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs @@ -42,7 +42,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications return false; } - if (_diskProvider.GetLastFileWrite(localEpisode.Path) > DateTime.UtcNow.AddMinutes(-5)) + if (_diskProvider.GetLastFileWriteUTC(localEpisode.Path) > DateTime.UtcNow.AddMinutes(-5)) { _logger.Trace("{0} appears to be unpacking still", localEpisode.Path); return false; diff --git a/src/NzbDrone.Core/MediaFiles/Events/SeriesAirDatedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/SeriesAirDatedEvent.cs new file mode 100644 index 000000000..d830dabb8 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/Events/SeriesAirDatedEvent.cs @@ -0,0 +1,15 @@ +using NzbDrone.Common.Messaging; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.MediaFiles.Events +{ + public class SeriesAirDatedEvent : IEvent + { + public Series Series { get; private set; } + + public SeriesAirDatedEvent(Series series) + { + Series = series; + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs index 4c5140c9a..8daafc574 100644 --- a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs +++ b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs @@ -139,7 +139,7 @@ namespace NzbDrone.Core.MediaFiles foreach (var file in _diskProvider.GetFiles(_configService.RecycleBin, SearchOption.TopDirectoryOnly)) { - if (_diskProvider.GetLastFileWrite(file).AddDays(7) > DateTime.UtcNow) + if (_diskProvider.GetLastFileWriteUTC(file).AddDays(7) > DateTime.UtcNow) { logger.Trace("File hasn't expired yet, skipping: {0}", file); continue; diff --git a/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs b/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs new file mode 100644 index 000000000..318bce24b --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/UpdateEpisodeFileService.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using NzbDrone.Common.Disk; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Instrumentation; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Instrumentation; +using NzbDrone.Core.MediaFiles.Commands; +using NzbDrone.Core.MediaFiles.Events; +using NzbDrone.Core.Messaging.Commands; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.MediaFiles +{ + public interface IUpdateEpisodeFileService + { + void ChangeFileDateToAirdate(EpisodeFile episodeFile, Series series); + } + + public class UpdateEpisodeFileService : IUpdateEpisodeFileService, + IExecute, + IHandle + { + private readonly IDiskProvider _diskProvider; + private readonly IConfigService _configService; + private readonly ISeriesService _seriesService; + private readonly IEpisodeService _episodeService; + private readonly IEventAggregator _eventAggregator; + private readonly Logger _logger; + + public UpdateEpisodeFileService(IDiskProvider diskProvider, + IConfigService configService, + ISeriesService seriesService, + IEpisodeService episodeService, + IEventAggregator eventAggregator, + Logger logger) + { + _diskProvider = diskProvider; + _configService = configService; + _seriesService = seriesService; + _episodeService = episodeService; + _eventAggregator = eventAggregator; + _logger = logger; + } + + public void ChangeFileDateToAirdate(EpisodeFile episodeFile, Series series) + { + var episode = new Episode(); + episode.AirDate = episodeFile.Episodes.Value.First().AirDate; + episode.EpisodeFile = episodeFile; + episode.EpisodeFileId = 1; + + var episodes = new List(); + episodes.Add(episode); + + ChangeFileDateToAirdate(episodes, series); + } + + private void ChangeFileDateToAirdate(List episodes, Series series) + { + if (!episodes.Any()) + { + _logger.ProgressDebug("{0} has no media files available to update with air dates", series.Title); + } + + else + { + var done = new List(); + + _logger.ProgressDebug("{0} ... checking {1} media file dates match air date", series.Title, episodes.Count); + + foreach (var episode in episodes) + { + if (episode.HasFile + && episode.EpisodeFile.IsLoaded + && ChangeFileDate(episode.EpisodeFile.Value.Path, episode.AirDate, series.AirTime)) + { + done.Add(episode); + } + } + + if (done.Any()) + { + _eventAggregator.PublishEvent(new SeriesAirDatedEvent(series)); + _logger.ProgressDebug("{0} had {1} of {2} media file dates changed to the date and time the episode aired", series.Title, done.Count, episodes.Count); + } + + else + { + _logger.ProgressDebug("{0} has all its media file dates matching the date each aired", series.Title); + } + } + } + + public void Execute(AirDateSeriesCommand message) + { + var seriesToAirDate = _seriesService.GetSeries(message.SeriesIds); + + foreach (var series in seriesToAirDate) + { + var episodes = _episodeService.EpisodesWithFiles(series.Id); + + ChangeFileDateToAirdate(episodes, series); + } + } + + public void Handle(SeriesScannedEvent message) + { + if (_configService.FileDateAiredDate) + { + var episodes = _episodeService.EpisodesWithFiles(message.Series.Id); + + ChangeFileDateToAirdate(episodes, message.Series); + } + } + + private bool ChangeFileDate(String filePath, String fileDate, String fileTime) + { + DateTime dateTime, oldDateTime; + bool result = false; + + if (DateTime.TryParse(fileDate + ' ' + fileTime, out dateTime)) + { + // avoiding false +ve checks and set date skewing by not using UTC (Windows) + oldDateTime = _diskProvider.GetLastFileWrite(filePath); + + if (!DateTime.Equals(dateTime, oldDateTime)) + { + try + { + _diskProvider.FileSetLastWriteTime(filePath, dateTime); + _diskProvider.FileSetLastAccessTime(filePath, dateTime); + _logger.Info("Date of file [{0}] changed from \"{1}\" to \"{2}\"", filePath, oldDateTime, dateTime); + result = true; + } + + catch (Exception ex) + { + _logger.WarnException("Unable to set date of file [" + filePath + "]", ex); + } + } + } + + else + { + _logger.Warn("Could not create valid date to set [{0}]", filePath); + } + + return result; + } + } +} diff --git a/src/NzbDrone.Core/MetadataSource/TraktProxy.cs b/src/NzbDrone.Core/MetadataSource/TraktProxy.cs index 86d7cc94f..2743ab083 100644 --- a/src/NzbDrone.Core/MetadataSource/TraktProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/TraktProxy.cs @@ -78,7 +78,7 @@ namespace NzbDrone.Core.MetadataSource series.Overview = show.overview; series.Runtime = show.runtime; series.Network = show.network; - series.AirTime = show.air_time_utc; + series.AirTime = show.air_time; series.TitleSlug = show.url.ToLower().Replace("http://trakt.tv/show/", ""); series.Status = GetSeriesStatus(show.status, show.ended); series.Ratings = GetRatings(show.ratings); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 640fef368..bf7965de1 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -308,6 +308,7 @@ + @@ -318,9 +319,11 @@ + + diff --git a/src/UI/Series/Editor/SeriesEditorFooterView.js b/src/UI/Series/Editor/SeriesEditorFooterView.js index cf02a09f1..0efc65562 100644 --- a/src/UI/Series/Editor/SeriesEditorFooterView.js +++ b/src/UI/Series/Editor/SeriesEditorFooterView.js @@ -10,7 +10,7 @@ define( 'AddSeries/RootFolders/RootFolderCollection', 'Shared/Toolbar/ToolbarLayout', 'AddSeries/RootFolders/RootFolderLayout', - 'Series/Editor/Rename/RenameSeriesView', + 'Series/Editor/UpdateFiles/UpdateFilesSeriesView', 'Config' ], function (_, Marionette, @@ -21,26 +21,26 @@ define( RootFolders, ToolbarLayout, RootFolderLayout, - RenameSeriesView, + UpdateFilesSeriesView, Config) { return Marionette.ItemView.extend({ template: 'Series/Editor/SeriesEditorFooterViewTemplate', ui: { - monitored : '.x-monitored', - qualityProfile: '.x-quality-profiles', - seasonFolder : '.x-season-folder', - rootFolder : '.x-root-folder', - selectedCount : '.x-selected-count', - saveButton : '.x-save', - renameButton : '.x-rename', - container : '.series-editor-footer' + monitored : '.x-monitored', + qualityProfile : '.x-quality-profiles', + seasonFolder : '.x-season-folder', + rootFolder : '.x-root-folder', + selectedCount : '.x-selected-count', + saveButton : '.x-save', + updateFilesButton: '.x-update-files', + container : '.series-editor-footer' }, events: { 'click .x-save' : '_updateAndSave', 'change .x-root-folder': '_rootFolderChanged', - 'click .x-rename' : '_rename' + 'click .x-update-files': '_updateFiles' }, templateHelpers: function () { @@ -119,7 +119,7 @@ define( this.ui.seasonFolder.attr('disabled', ''); this.ui.rootFolder.attr('disabled', ''); this.ui.saveButton.attr('disabled', ''); - this.ui.renameButton.attr('disabled', ''); + this.ui.updateFilesButton.attr('disabled', ''); } else { @@ -128,7 +128,7 @@ define( this.ui.seasonFolder.removeAttr('disabled', ''); this.ui.rootFolder.removeAttr('disabled', ''); this.ui.saveButton.removeAttr('disabled', ''); - this.ui.renameButton.removeAttr('disabled', ''); + this.ui.updateFilesButton.removeAttr('disabled', ''); } }, @@ -162,12 +162,12 @@ define( }); }, - _rename: function () { + _updateFiles: function () { var selected = this.editorGrid.getSelectedModels(); - var renameSeriesView = new RenameSeriesView({ series: selected }); - this.listenToOnce(renameSeriesView, 'seriesRenamed', this._afterSave); + var updateFilesSeriesView = new UpdateFilesSeriesView({ series: selected }); + this.listenToOnce(updateFilesSeriesView, 'updatingFiles', this._afterSave); - vent.trigger(vent.Commands.OpenModalCommand, renameSeriesView); + vent.trigger(vent.Commands.OpenModalCommand, updateFilesSeriesView); } }); }); diff --git a/src/UI/Series/Editor/SeriesEditorFooterViewTemplate.html b/src/UI/Series/Editor/SeriesEditorFooterViewTemplate.html index 88a1d382c..48995092d 100644 --- a/src/UI/Series/Editor/SeriesEditorFooterViewTemplate.html +++ b/src/UI/Series/Editor/SeriesEditorFooterViewTemplate.html @@ -45,7 +45,7 @@ 0 series selected - + \ No newline at end of file diff --git a/src/UI/Series/Editor/Rename/RenameSeriesView.js b/src/UI/Series/Editor/UpdateFiles/UpdateFilesSeriesView.js similarity index 58% rename from src/UI/Series/Editor/Rename/RenameSeriesView.js rename to src/UI/Series/Editor/UpdateFiles/UpdateFilesSeriesView.js index c573433bf..e0e7b55ba 100644 --- a/src/UI/Series/Editor/Rename/RenameSeriesView.js +++ b/src/UI/Series/Editor/UpdateFiles/UpdateFilesSeriesView.js @@ -9,10 +9,11 @@ define( ], function (_, vent, Backbone, Marionette, CommandController) { return Marionette.ItemView.extend({ - template: 'Series/Editor/Rename/RenameSeriesViewTemplate', + template: 'Series/Editor/UpdateFiles/UpdateFilesSeriesViewTemplate', events: { - 'click .x-confirm-rename': '_rename' + 'click .x-confirm-rename': '_rename', + 'click .x-confirm-airdate': '_setFileAirDate' }, initialize: function (options) { @@ -29,7 +30,19 @@ define( seriesIds : seriesIds }); - this.trigger('seriesRenamed'); + this.trigger('updatingFiles'); + vent.trigger(vent.Commands.CloseModalCommand); + }, + + _setFileAirDate: function () { + var seriesIds = _.pluck(this.series, 'id'); + + CommandController.Execute('AirDateSeries', { + name: 'AirDateSeries', + seriesIds: seriesIds + }); + + this.trigger('updatingFiles'); vent.trigger(vent.Commands.CloseModalCommand); } }); diff --git a/src/UI/Series/Editor/Rename/RenameSeriesViewTemplate.html b/src/UI/Series/Editor/UpdateFiles/UpdateFilesSeriesViewTemplate.html similarity index 56% rename from src/UI/Series/Editor/Rename/RenameSeriesViewTemplate.html rename to src/UI/Series/Editor/UpdateFiles/UpdateFilesSeriesViewTemplate.html index e9c2e58c7..836c70310 100644 --- a/src/UI/Series/Editor/Rename/RenameSeriesViewTemplate.html +++ b/src/UI/Series/Editor/UpdateFiles/UpdateFilesSeriesViewTemplate.html @@ -1,23 +1,24 @@  - +
+ +
+
+
From 8885bbb60f1f2e81e5fb0cf9d6abd1b1f5bddd61 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 8 Mar 2014 21:28:40 -0800 Subject: [PATCH 06/34] OS X and linux can be treated separately --- src/NzbDrone.Api/System/SystemModule.cs | 12 ++- .../EnsureThat/EnsureStringExtensions.cs | 2 +- .../EnvironmentInfo/AppFolderFactory.cs | 2 +- .../EnvironmentInfo/AppFolderInfo.cs | 2 +- src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs | 81 +++++++++++++++---- .../EnvironmentInfo/RuntimeInfo.cs | 2 +- .../Instrumentation/LogTargets.cs | 2 +- src/NzbDrone.Common/PathEqualityComparer.cs | 2 +- src/NzbDrone.Common/PathExtensions.cs | 8 +- .../Lifecycle/LifecycleService.cs | 2 +- .../NotUnpackingSpecification.cs | 2 +- .../MediaFiles/RecycleBinProvider.cs | 2 +- .../Update/UpdateCheckService.cs | 2 +- .../AccessControl/FirewallAdapter.cs | 2 +- src/NzbDrone.Host/ApplicationServer.cs | 4 +- src/NzbDrone.Host/Bootstrap.cs | 4 +- src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs | 2 +- src/NzbDrone.Test.Common/StringExtensions.cs | 2 +- src/NzbDrone.Test.Common/TestBase.cs | 4 +- src/UI/.idea/jsLinters/jshint.xml | 4 +- src/UI/Handlebars/Helpers/System.js | 4 +- .../Permissions/PermissionsViewTemplate.html | 4 +- 22 files changed, 101 insertions(+), 50 deletions(-) diff --git a/src/NzbDrone.Api/System/SystemModule.cs b/src/NzbDrone.Api/System/SystemModule.cs index 5acd4d881..b56f1d14b 100644 --- a/src/NzbDrone.Api/System/SystemModule.cs +++ b/src/NzbDrone.Api/System/SystemModule.cs @@ -16,7 +16,11 @@ namespace NzbDrone.Api.System private readonly IConfigFileProvider _configFileProvider; private readonly IDatabase _database; - public SystemModule(IAppFolderInfo appFolderInfo, IRuntimeInfo runtimeInfo, IRouteCacheProvider routeCacheProvider, IConfigFileProvider configFileProvider, IDatabase database) + public SystemModule(IAppFolderInfo appFolderInfo, + IRuntimeInfo runtimeInfo, + IRouteCacheProvider routeCacheProvider, + IConfigFileProvider configFileProvider, + IDatabase database) : base("system") { _appFolderInfo = appFolderInfo; @@ -41,8 +45,10 @@ namespace NzbDrone.Api.System StartupPath = _appFolderInfo.StartUpFolder, AppData = _appFolderInfo.GetAppDataPath(), OsVersion = OsInfo.Version.ToString(), + IsMonoRuntime = OsInfo.IsMono, IsMono = OsInfo.IsMono, - IsLinux = OsInfo.IsLinux, + IsLinux = OsInfo.IsMono, + IsOsx = OsInfo.IsOsx, IsWindows = OsInfo.IsWindows, Branch = _configFileProvider.Branch, Authentication = _configFileProvider.AuthenticationEnabled, @@ -50,10 +56,8 @@ namespace NzbDrone.Api.System SqliteVersion = _database.Version, UrlBase = _configFileProvider.UrlBase }.AsResponse(); - } - private Response GetRoutes() { return _routeCacheProvider.GetCache().Values.AsResponse(); diff --git a/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs b/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs index ede83ca40..d8bade8cf 100644 --- a/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs +++ b/src/NzbDrone.Common/EnsureThat/EnsureStringExtensions.cs @@ -100,7 +100,7 @@ namespace NzbDrone.Common.EnsureThat if (param.Value.IsPathValid()) return param; - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { throw ExceptionFactory.CreateForParamValidation(param.Name, string.Format("value [{0}] is not a valid *nix path. paths must start with /", param.Value)); } diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs index c49d4864b..d45f4269f 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderFactory.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Common.EnvironmentInfo { _diskProvider.EnsureFolder(_appFolderInfo.AppDataFolder); - if (!OsInfo.IsLinux) + if (!OsInfo.IsMono) { SetPermissions(); } diff --git a/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs index 3a5bcd019..da1e7cfaa 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/AppFolderInfo.cs @@ -17,7 +17,7 @@ namespace NzbDrone.Common.EnvironmentInfo public AppFolderInfo(IStartupContext startupContext) { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { DATA_SPECIAL_FOLDER = Environment.SpecialFolder.ApplicationData; } diff --git a/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs index 3b769bfea..16894f00c 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/OsInfo.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.InteropServices; namespace NzbDrone.Common.EnvironmentInfo { @@ -7,34 +8,80 @@ namespace NzbDrone.Common.EnvironmentInfo static OsInfo() { - Version = Environment.OSVersion.Version; - IsMono = Type.GetType("Mono.Runtime") != null; + var platform = (int)Environment.OSVersion.Platform; - int platform = (int)Environment.OSVersion.Platform; - IsLinux = (platform == 4) || (platform == 6) || (platform == 128); - + Version = Environment.OSVersion.Version; + + IsMonoRuntime = Type.GetType("Mono.Runtime") != null; + IsMono = (platform == 4) || (platform == 6) || (platform == 128); + IsOsx = IsRunningOnMac(); + IsLinux = IsMono && !IsOsx; + IsWindows = !IsMono; + + FirstDayOfWeek = DateTime.Today.GetFirstDayOfWeek().DayOfWeek; + + if (!IsMono) + { + Os = Os.Windows; + } + + else + { + Os = IsOsx ? Os.Osx : Os.Linux; + } } public static Version Version { get; private set; } - + public static bool IsMonoRuntime { get; private set; } public static bool IsMono { get; private set; } - public static bool IsLinux { get; private set; } + public static bool IsOsx { get; private set; } + public static bool IsWindows { get; private set; } + public static Os Os { get; private set; } + public static DayOfWeek FirstDayOfWeek { get; private set; } - public static bool IsWindows - { - get - { - return !IsLinux; - } - } + //Borrowed from: https://github.com/jpobst/Pinta/blob/master/Pinta.Core/Managers/SystemManager.cs + //From Managed.Windows.Forms/XplatUI + [DllImport("libc")] + static extern int uname(IntPtr buf); - public static DayOfWeek FirstDayOfWeek + static bool IsRunningOnMac() { - get + var buf = IntPtr.Zero; + + try { - return DateTime.Today.GetFirstDayOfWeek().DayOfWeek; + buf = Marshal.AllocHGlobal(8192); + // This is a hacktastic way of getting sysname from uname () + if (uname(buf) == 0) + { + var os = Marshal.PtrToStringAnsi(buf); + + if (os == "Darwin") + { + return true; + } + } } + catch + { + } + finally + { + if (buf != IntPtr.Zero) + { + Marshal.FreeHGlobal(buf); + } + } + + return false; } } + + public enum Os + { + Windows, + Linux, + Osx + } } \ No newline at end of file diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs index 82369c35b..8cef57af6 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -78,7 +78,7 @@ namespace NzbDrone.Common.EnvironmentInfo return (OsInfo.IsWindows && IsUserInteractive && ProcessName.Equals(ProcessProvider.NZB_DRONE_CONSOLE_PROCESS_NAME, StringComparison.InvariantCultureIgnoreCase)) || - OsInfo.IsLinux; + OsInfo.IsMono; } } diff --git a/src/NzbDrone.Common/Instrumentation/LogTargets.cs b/src/NzbDrone.Common/Instrumentation/LogTargets.cs index f44ce456c..67e8f69d3 100644 --- a/src/NzbDrone.Common/Instrumentation/LogTargets.cs +++ b/src/NzbDrone.Common/Instrumentation/LogTargets.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Common.Instrumentation } else { - if (inConsole && (OsInfo.IsLinux || new RuntimeInfo(null, new ServiceProvider(new ProcessProvider())).IsUserInteractive)) + if (inConsole && (OsInfo.IsMono || new RuntimeInfo(null, new ServiceProvider(new ProcessProvider())).IsUserInteractive)) { RegisterConsole(); } diff --git a/src/NzbDrone.Common/PathEqualityComparer.cs b/src/NzbDrone.Common/PathEqualityComparer.cs index ce55c50e8..88df4b480 100644 --- a/src/NzbDrone.Common/PathEqualityComparer.cs +++ b/src/NzbDrone.Common/PathEqualityComparer.cs @@ -20,7 +20,7 @@ namespace NzbDrone.Common public int GetHashCode(string obj) { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { return obj.CleanFilePath().GetHashCode(); } diff --git a/src/NzbDrone.Common/PathExtensions.cs b/src/NzbDrone.Common/PathExtensions.cs index c08770fc8..16a9bddd1 100644 --- a/src/NzbDrone.Common/PathExtensions.cs +++ b/src/NzbDrone.Common/PathExtensions.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Common var info = new FileInfo(path.Trim()); - if (!OsInfo.IsLinux && info.FullName.StartsWith(@"\\")) //UNC + if (!OsInfo.IsMono && info.FullName.StartsWith(@"\\")) //UNC { return info.FullName.TrimEnd('/', '\\', ' '); } @@ -39,7 +39,7 @@ namespace NzbDrone.Common public static bool PathEquals(this string firstPath, string secondPath) { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { if (firstPath.Equals(secondPath)) return true; return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath()); @@ -58,7 +58,7 @@ namespace NzbDrone.Common return false; } - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { return path.StartsWith(Path.DirectorySeparatorChar.ToString()); } @@ -97,7 +97,7 @@ namespace NzbDrone.Common public static string GetActualCasing(this string path) { - if (OsInfo.IsLinux || path.StartsWith("\\")) + if (OsInfo.IsMono || path.StartsWith("\\")) { return path; } diff --git a/src/NzbDrone.Core/Lifecycle/LifecycleService.cs b/src/NzbDrone.Core/Lifecycle/LifecycleService.cs index 25199b49f..8b2f3a21e 100644 --- a/src/NzbDrone.Core/Lifecycle/LifecycleService.cs +++ b/src/NzbDrone.Core/Lifecycle/LifecycleService.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Lifecycle { _logger.Info("Restart requested."); - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { _processProvider.SpawnNewProcess(_runtimeInfo.ExecutingApplication, "--terminateexisting --nobrowser"); } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs index 50279a4e2..c5ebd44ec 100644 --- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications { if (Directory.GetParent(localEpisode.Path).Name.StartsWith(workingFolder)) { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { _logger.Trace("{0} is still being unpacked", localEpisode.Path); return false; diff --git a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs index 4c5140c9a..0dc62b613 100644 --- a/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs +++ b/src/NzbDrone.Core/MediaFiles/RecycleBinProvider.cs @@ -73,7 +73,7 @@ namespace NzbDrone.Core.MediaFiles { logger.Info("Recycling Bin has not been configured, deleting permanently."); - if (!OsInfo.IsLinux) + if (!OsInfo.IsMono) { logger.Trace(_diskProvider.GetFileAttributes(path)); } diff --git a/src/NzbDrone.Core/Update/UpdateCheckService.cs b/src/NzbDrone.Core/Update/UpdateCheckService.cs index 32cb64be2..e8d853305 100644 --- a/src/NzbDrone.Core/Update/UpdateCheckService.cs +++ b/src/NzbDrone.Core/Update/UpdateCheckService.cs @@ -27,7 +27,7 @@ namespace NzbDrone.Core.Update public UpdatePackage AvailableUpdate() { - if (OsInfo.IsLinux) return null; + if (OsInfo.IsMono) return null; var latestAvailable = _updatePackageProvider.GetLatestUpdate(_configFileProvider.Branch, BuildInfo.Version); diff --git a/src/NzbDrone.Host/AccessControl/FirewallAdapter.cs b/src/NzbDrone.Host/AccessControl/FirewallAdapter.cs index c252e3e9e..556f47baf 100644 --- a/src/NzbDrone.Host/AccessControl/FirewallAdapter.cs +++ b/src/NzbDrone.Host/AccessControl/FirewallAdapter.cs @@ -90,7 +90,7 @@ namespace NzbDrone.Host.AccessControl private bool IsFirewallEnabled() { - if (OsInfo.IsLinux) return false; + if (OsInfo.IsMono) return false; try { diff --git a/src/NzbDrone.Host/ApplicationServer.cs b/src/NzbDrone.Host/ApplicationServer.cs index 946334ec6..1e6a5f713 100644 --- a/src/NzbDrone.Host/ApplicationServer.cs +++ b/src/NzbDrone.Host/ApplicationServer.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Host public void Start() { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { Console.CancelKeyPress += (sender, eventArgs) => _processProvider.Kill(_processProvider.GetCurrentProcess().Id); } @@ -90,7 +90,7 @@ namespace NzbDrone.Host public void Handle(ApplicationShutdownRequested message) { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { _processProvider.Kill(_processProvider.GetCurrentProcess().Id); } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 1b0d9fa70..7a4ef8ff5 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -106,12 +106,12 @@ namespace NzbDrone.Host return ApplicationModes.Help; } - if (!OsInfo.IsLinux && startupContext.InstallService) + if (!OsInfo.IsMono && startupContext.InstallService) { return ApplicationModes.InstallService; } - if (!OsInfo.IsLinux && startupContext.UninstallService) + if (!OsInfo.IsMono && startupContext.UninstallService) { return ApplicationModes.UninstallService; } diff --git a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs index 2c7e4b4f7..437a9bde4 100644 --- a/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs +++ b/src/NzbDrone.Test.Common/AutoMoq/AutoMoqer.cs @@ -173,7 +173,7 @@ namespace NzbDrone.Test.Common.AutoMoq { var assemblyName = "NzbDrone.Windows"; - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { assemblyName = "NzbDrone.Mono"; } diff --git a/src/NzbDrone.Test.Common/StringExtensions.cs b/src/NzbDrone.Test.Common/StringExtensions.cs index 7ec3f4698..09b9b5b2d 100644 --- a/src/NzbDrone.Test.Common/StringExtensions.cs +++ b/src/NzbDrone.Test.Common/StringExtensions.cs @@ -7,7 +7,7 @@ namespace NzbDrone.Test.Common { public static string AsOsAgnostic(this string path) { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { if (path.Length > 2 && path[1] == ':') { diff --git a/src/NzbDrone.Test.Common/TestBase.cs b/src/NzbDrone.Test.Common/TestBase.cs index 470cba8e1..c42fca8a9 100644 --- a/src/NzbDrone.Test.Common/TestBase.cs +++ b/src/NzbDrone.Test.Common/TestBase.cs @@ -124,7 +124,7 @@ namespace NzbDrone.Test.Common protected void WindowsOnly() { - if (OsInfo.IsLinux) + if (OsInfo.IsMono) { throw new IgnoreException("windows specific test"); } @@ -133,7 +133,7 @@ namespace NzbDrone.Test.Common protected void LinuxOnly() { - if (!OsInfo.IsLinux) + if (!OsInfo.IsMono) { throw new IgnoreException("linux specific test"); } diff --git a/src/UI/.idea/jsLinters/jshint.xml b/src/UI/.idea/jsLinters/jshint.xml index 4e0df49ad..e85398a55 100644 --- a/src/UI/.idea/jsLinters/jshint.xml +++ b/src/UI/.idea/jsLinters/jshint.xml @@ -8,16 +8,16 @@
-{{/if_linux}} \ No newline at end of file +{{/if_mono}} \ No newline at end of file From 176f3e05635f07f97b29b439043128f5f359a29b Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 8 Mar 2014 22:11:38 -0800 Subject: [PATCH 07/34] Log startup location, log number of results from feed --- src/NzbDrone.Core/Indexers/IndexerFetchService.cs | 2 +- src/NzbDrone.Host/Bootstrap.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/Indexers/IndexerFetchService.cs b/src/NzbDrone.Core/Indexers/IndexerFetchService.cs index 7009e748c..67da61c5d 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFetchService.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFetchService.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Indexers var result = Fetch(indexer, indexer.RecentFeed); - _logger.Debug("Finished processing feeds from " + indexer); + _logger.Debug("Finished processing feeds from {0} found {1} releases", indexer, result.Count); return result; } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 7a4ef8ff5..cac59c291 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Host GlobalExceptionHandlers.Register(); IgnoreCertErrorPolicy.Register(); - Logger.Info("Starting NzbDrone Console. Version {0}", Assembly.GetExecutingAssembly().GetName().Version); + Logger.Info("Starting NzbDrone - {0} - Version {1}", Assembly.GetCallingAssembly().Location, Assembly.GetExecutingAssembly().GetName().Version); if (!PlatformValidation.IsValidate(userAlert)) { From 57912ab86de69a8c90dc8de90b51ab91a47c34dc Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 9 Mar 2014 00:22:35 -0800 Subject: [PATCH 08/34] Fixed update test, send os when requesting update packages --- src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs | 2 +- src/NzbDrone.Core/Update/UpdatePackageProvider.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs index 810dc8661..f02a8368d 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.UpdateTests private readonly UpdatePackage _updatePackage = new UpdatePackage { FileName = "NzbDrone.develop.2.0.0.zip", - Url = "http://update.nzbdrone.com/v2/develop/NzbDrone.develop.zip", + Url = "http://update.nzbdrone.com/v2/develop/windows/NzbDrone.develop.zip", Version = new Version("2.0.0") }; diff --git a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs index e95d4c6fa..0b436adfb 100644 --- a/src/NzbDrone.Core/Update/UpdatePackageProvider.cs +++ b/src/NzbDrone.Core/Update/UpdatePackageProvider.cs @@ -22,6 +22,7 @@ namespace NzbDrone.Core.Update var request = new RestRequest("/v1/update/{branch}"); request.AddParameter("version", currentVersion); + request.AddParameter("os", OsInfo.Os.ToString().ToLowerInvariant()); request.AddUrlSegment("branch", branch); var update = restClient.ExecuteAndValidate(request); @@ -38,6 +39,7 @@ namespace NzbDrone.Core.Update var request = new RestRequest("/v1/update/{branch}/changes"); request.AddParameter("majorVersion", BuildInfo.Version.Major); + request.AddParameter("os", OsInfo.Os.ToString().ToLowerInvariant()); request.AddUrlSegment("branch", branch); var updates = restClient.ExecuteAndValidate>(request); From d3621fca71dfd098d446d5b2aa1850c41434bfb8 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 9 Mar 2014 01:08:56 -0800 Subject: [PATCH 09/34] Run update tests on linux --- src/NzbDrone.Common/ArchiveProvider.cs | 31 ++++++++++++++++++- .../UpdateTests/UpdateServiceFixture.cs | 28 ++++++++++++----- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/NzbDrone.Common/ArchiveProvider.cs b/src/NzbDrone.Common/ArchiveProvider.cs index 629d3c6bb..f15cc6899 100644 --- a/src/NzbDrone.Common/ArchiveProvider.cs +++ b/src/NzbDrone.Common/ArchiveProvider.cs @@ -1,8 +1,11 @@ using System; using System.IO; using ICSharpCode.SharpZipLib.Core; +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tar; using ICSharpCode.SharpZipLib.Zip; using NLog; +using NzbDrone.Common.EnvironmentInfo; namespace NzbDrone.Common { @@ -24,6 +27,21 @@ namespace NzbDrone.Common { _logger.Trace("Extracting archive [{0}] to [{1}]", compressedFile, destination); + if (OsInfo.IsWindows) + { + ExtractZip(compressedFile, destination); + } + + else + { + ExtractTgz(compressedFile, destination); + } + + _logger.Trace("Extraction complete."); + } + + private void ExtractZip(string compressedFile, string destination) + { using (var fileStream = File.OpenRead(compressedFile)) { var zipFile = new ZipFile(fileStream); @@ -64,8 +82,19 @@ namespace NzbDrone.Common } } } + } - _logger.Trace("Extraction complete."); + private void ExtractTgz(string compressedFile, string destination) + { + Stream inStream = File.OpenRead(compressedFile); + Stream gzipStream = new GZipInputStream(inStream); + + TarArchive tarArchive = TarArchive.CreateInputTarArchive(gzipStream); + tarArchive.ExtractContents(destination); + tarArchive.Close(); + + gzipStream.Close(); + inStream.Close(); } private void OnZipError(TestStatus status, string message) diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs index f02a8368d..db7f7c530 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs @@ -21,17 +21,30 @@ namespace NzbDrone.Core.Test.UpdateTests { private string _sandboxFolder; - private readonly UpdatePackage _updatePackage = new UpdatePackage - { - FileName = "NzbDrone.develop.2.0.0.zip", - Url = "http://update.nzbdrone.com/v2/develop/windows/NzbDrone.develop.zip", - Version = new Version("2.0.0") - }; + private UpdatePackage _updatePackage; [SetUp] public void Setup() { - WindowsOnly(); + if (OsInfo.IsLinux) + { + _updatePackage = new UpdatePackage + { + FileName = "NzbDrone.develop.2.0.0.0.tar.gz", + Url = "http://update.nzbdrone.com/v2/develop/mono/NzbDrone.develop.tar.gz", + Version = new Version("2.0.0.0") + }; + } + + else + { + _updatePackage = new UpdatePackage + { + FileName = "NzbDrone.develop.2.0.0.0.zip", + Url = "http://update.nzbdrone.com/v2/develop/windows/NzbDrone.develop.zip", + Version = new Version("2.0.0.0") + }; + } Mocker.GetMock().SetupGet(c => c.TempFolder).Returns(TempFolder); Mocker.GetMock().Setup(c => c.AvailableUpdate()).Returns(_updatePackage); @@ -42,7 +55,6 @@ namespace NzbDrone.Core.Test.UpdateTests } - [Test] public void should_delete_sandbox_before_update_if_folder_exists() { From d6adf2ebaf3f49c54c59d1e1e7e5294a23e46a2a Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 9 Mar 2014 01:44:57 -0800 Subject: [PATCH 10/34] Added TestArchive.tar.gz --- src/NzbDrone.Core.Test/Files/TestArchive.tar.gz | Bin 0 -> 283 bytes src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 3 +++ .../DiskProviderTests/ArchiveProviderFixture.cs | 5 ++++- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core.Test/Files/TestArchive.tar.gz diff --git a/src/NzbDrone.Core.Test/Files/TestArchive.tar.gz b/src/NzbDrone.Core.Test/Files/TestArchive.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..b37bf29717d5e3f25b7ca1f55893ce8133f9269f GIT binary patch literal 283 zcmV+$0p$K4iwFozHyl#}090jjbU|`sXlZt3E_7jX0PUDv3W7ish37eF53_>0cl? zQvSdCUrLEa{`&y=A2*}?|FaNI@}HgmDZ_ss!2h@z@?Qn*f4S>_`2XjH!To>oUxn&_ h$bUZ||Knzq{~`Kc0{?vg{{a9XP98}-xV!)&0028uizWa7 literal 0 HcmV?d00001 diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index d2b866928..b21c4cfd2 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -362,6 +362,9 @@ Always + + Always + Always diff --git a/src/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ArchiveProviderFixture.cs b/src/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ArchiveProviderFixture.cs index 9cf514eb1..a9f3e2f0d 100644 --- a/src/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ArchiveProviderFixture.cs +++ b/src/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/ArchiveProviderFixture.cs @@ -2,6 +2,7 @@ using NUnit.Framework; using NzbDrone.Common; using System.IO; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.ProviderTests.DiskProviderTests @@ -13,7 +14,9 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskProviderTests public void Should_extract_to_correct_folder() { var destination = Path.Combine(TempFolder, "destination"); - Subject.Extract(GetTestFilePath("TestArchive.zip"), destination); + var testArchive = OsInfo.IsWindows ? "TestArchive.zip" : "TestArchive.tar.gz"; + + Subject.Extract(GetTestFilePath(testArchive), destination); var destinationFolder = new DirectoryInfo(destination); From 565a1720530282f6f05f260e9d9a5eb5ae29ffeb Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 9 Mar 2014 01:51:27 -0800 Subject: [PATCH 11/34] Fixed casing of folder --- src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs index db7f7c530..357463bdf 100644 --- a/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs +++ b/src/NzbDrone.Core.Test/UpdateTests/UpdateServiceFixture.cs @@ -148,7 +148,7 @@ namespace NzbDrone.Core.Test.UpdateTests updateSubFolder.Refresh(); updateSubFolder.Exists.Should().BeTrue(); - updateSubFolder.GetDirectories("nzbdrone").Should().HaveCount(1); + updateSubFolder.GetDirectories("NzbDrone").Should().HaveCount(1); updateSubFolder.GetDirectories().Should().HaveCount(1); updateSubFolder.GetFiles().Should().NotBeEmpty(); } From ce13be3d4347496b5a39b4f45190378e6de42195 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 9 Mar 2014 14:23:48 -0700 Subject: [PATCH 12/34] Fixed build.ps1 for osx package --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index c690b62bb..2656822ae 100644 --- a/build.ps1 +++ b/build.ps1 @@ -119,7 +119,7 @@ Function PackageOsx() if(Test-Path $outputFolderOsx) { - Remove-Item -Recurse -Force $outputFolderMono -ErrorAction Continue + Remove-Item -Recurse -Force $outputFolderOsx -ErrorAction Continue } Copy-Item $outputFolderMono $outputFolderOsx -recurse From c2087af8c95b2aa7c837d65c5815801b6ee7826c Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 9 Mar 2014 22:35:50 -0700 Subject: [PATCH 13/34] Gracefully exit on restart instead of forcibly killing it --- .../Messaging/MessageBroker.cs | 8 ++++ src/NzbDrone.Api/Config/HostConfigResource.cs | 1 + .../EnvironmentInfo/RuntimeInfo.cs | 2 + .../EnvironmentInfo/StartupContext.cs | 1 + .../Configuration/ConfigFileProvider.cs | 6 +++ .../Lifecycle/LifecycleService.cs | 10 ----- src/NzbDrone.Host/ApplicationServer.cs | 13 ++++--- src/NzbDrone.Host/Bootstrap.cs | 13 ++++--- src/NzbDrone.Host/NzbDrone.Host.csproj | 1 + src/NzbDrone.Host/SpinService.cs | 36 ++++++++++++++++++ .../Settings/General/GeneralViewTemplate.html | 23 +++++++++++ src/UpgradeLog.htm | Bin 60810 -> 0 bytes src/UpgradeLog2.htm | Bin 60810 -> 0 bytes 13 files changed, 92 insertions(+), 22 deletions(-) create mode 100644 src/NzbDrone.Host/SpinService.cs delete mode 100644 src/UpgradeLog.htm delete mode 100644 src/UpgradeLog2.htm diff --git a/src/Microsoft.AspNet.SignalR.Core/Messaging/MessageBroker.cs b/src/Microsoft.AspNet.SignalR.Core/Messaging/MessageBroker.cs index 76c24161d..8995f96bc 100644 --- a/src/Microsoft.AspNet.SignalR.Core/Messaging/MessageBroker.cs +++ b/src/Microsoft.AspNet.SignalR.Core/Messaging/MessageBroker.cs @@ -295,6 +295,14 @@ namespace Microsoft.AspNet.SignalR.Messaging Trace.TraceEvent(TraceEventType.Verbose, 0, "Dispoing the broker"); + //Check if OS is not Windows and exit + var platform = (int)Environment.OSVersion.Platform; + + if ((platform == 4) || (platform == 6) || (platform == 128)) + { + return; + } + // Wait for all threads to stop working WaitForDrain(); diff --git a/src/NzbDrone.Api/Config/HostConfigResource.cs b/src/NzbDrone.Api/Config/HostConfigResource.cs index 8fc4151d9..3387ba421 100644 --- a/src/NzbDrone.Api/Config/HostConfigResource.cs +++ b/src/NzbDrone.Api/Config/HostConfigResource.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Api.Config public String Password { get; set; } public String LogLevel { get; set; } public String Branch { get; set; } + public Boolean AutoUpdate { get; set; } public String ApiKey { get; set; } public Boolean Torrent { get; set; } public String SslCertHash { get; set; } diff --git a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs index 8cef57af6..679fe2f1c 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/RuntimeInfo.cs @@ -16,6 +16,7 @@ namespace NzbDrone.Common.EnvironmentInfo bool IsWindowsService { get; } bool IsConsole { get; } bool IsRunning { get; set; } + bool RestartPending { get; set; } string ExecutingApplication { get; } } @@ -83,6 +84,7 @@ namespace NzbDrone.Common.EnvironmentInfo } public bool IsRunning { get; set; } + public bool RestartPending { get; set; } public string ExecutingApplication { get; private set; } public static bool IsProduction { get; private set; } diff --git a/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs b/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs index 3331b39e4..dbf4e6d65 100644 --- a/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs +++ b/src/NzbDrone.Common/EnvironmentInfo/StartupContext.cs @@ -18,6 +18,7 @@ namespace NzbDrone.Common.EnvironmentInfo internal const string UNINSTALL_SERVICE = "u"; public const string HELP = "?"; public const string TERMINATE = "terminateexisting"; + public const string RESTART = "restart"; public StartupContext(params string[] args) { diff --git a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs index f82da6eb1..9e8f5dd1b 100644 --- a/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs +++ b/src/NzbDrone.Core/Configuration/ConfigFileProvider.cs @@ -28,6 +28,7 @@ namespace NzbDrone.Core.Configuration string Password { get; } string LogLevel { get; } string Branch { get; } + bool AutoUpdate { get; } string ApiKey { get; } bool Torrent { get; } string SslCertHash { get; } @@ -133,6 +134,11 @@ namespace NzbDrone.Core.Configuration get { return GetValue("Branch", "master").ToLowerInvariant(); } } + public bool AutoUpdate + { + get { return GetValueBoolean("AutoUpdate", false, persist: false); } + } + public string Username { get { return GetValue("Username", ""); } diff --git a/src/NzbDrone.Core/Lifecycle/LifecycleService.cs b/src/NzbDrone.Core/Lifecycle/LifecycleService.cs index 8b2f3a21e..1d02490c6 100644 --- a/src/NzbDrone.Core/Lifecycle/LifecycleService.cs +++ b/src/NzbDrone.Core/Lifecycle/LifecycleService.cs @@ -48,22 +48,12 @@ namespace NzbDrone.Core.Lifecycle { _logger.Info("Restart requested."); - if (OsInfo.IsMono) - { - _processProvider.SpawnNewProcess(_runtimeInfo.ExecutingApplication, "--terminateexisting --nobrowser"); - } - _eventAggregator.PublishEvent(new ApplicationShutdownRequested(true)); if (_runtimeInfo.IsWindowsService) { _serviceProvider.Restart(ServiceProvider.NZBDRONE_SERVICE_NAME); } - - else - { - _processProvider.SpawnNewProcess(_runtimeInfo.ExecutingApplication, "--terminateexisting --nobrowser"); - } } } } diff --git a/src/NzbDrone.Host/ApplicationServer.cs b/src/NzbDrone.Host/ApplicationServer.cs index 1e6a5f713..c299c4870 100644 --- a/src/NzbDrone.Host/ApplicationServer.cs +++ b/src/NzbDrone.Host/ApplicationServer.cs @@ -55,7 +55,7 @@ namespace NzbDrone.Host { if (OsInfo.IsMono) { - Console.CancelKeyPress += (sender, eventArgs) => _processProvider.Kill(_processProvider.GetCurrentProcess().Id); + Console.CancelKeyPress += (sender, eventArgs) => LogManager.Configuration = null; } _runtimeInfo.IsRunning = true; @@ -90,13 +90,14 @@ namespace NzbDrone.Host public void Handle(ApplicationShutdownRequested message) { - if (OsInfo.IsMono) + if (!_runtimeInfo.IsWindowsService) { - _processProvider.Kill(_processProvider.GetCurrentProcess().Id); - } + if (message.Restarting) + { + _runtimeInfo.RestartPending = true; + } - if (!_runtimeInfo.IsWindowsService && !message.Restarting) - { + LogManager.Configuration = null; Shutdown(); } } diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index cac59c291..ca277851c 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -5,6 +5,7 @@ using NLog; using NzbDrone.Common.Composition; using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.Instrumentation; +using NzbDrone.Common.Processes; using NzbDrone.Common.Security; using NzbDrone.Core.Datastore; @@ -59,6 +60,11 @@ namespace NzbDrone.Host { if (!IsInUtilityMode(applicationModes)) { + if (startupContext.Flags.Contains(StartupContext.RESTART)) + { + Thread.Sleep(2000); + } + EnsureSingleInstance(applicationModes == ApplicationModes.Service, startupContext); } @@ -73,12 +79,7 @@ namespace NzbDrone.Host return; } - var runTimeInfo = _container.Resolve(); - - while (runTimeInfo.IsRunning) - { - Thread.Sleep(1000); - } + _container.Resolve().Spin(); } private static void EnsureSingleInstance(bool isService, StartupContext startupContext) diff --git a/src/NzbDrone.Host/NzbDrone.Host.csproj b/src/NzbDrone.Host/NzbDrone.Host.csproj index 703828a2f..861ae81e9 100644 --- a/src/NzbDrone.Host/NzbDrone.Host.csproj +++ b/src/NzbDrone.Host/NzbDrone.Host.csproj @@ -101,6 +101,7 @@ + diff --git a/src/NzbDrone.Host/SpinService.cs b/src/NzbDrone.Host/SpinService.cs new file mode 100644 index 000000000..8b07dfbc2 --- /dev/null +++ b/src/NzbDrone.Host/SpinService.cs @@ -0,0 +1,36 @@ +using System.Threading; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Processes; + +namespace NzbDrone.Host +{ + public interface IWaitForExit + { + void Spin(); + } + + public class SpinService : IWaitForExit + { + private readonly IRuntimeInfo _runtimeInfo; + private readonly IProcessProvider _processProvider; + + public SpinService(IRuntimeInfo runtimeInfo, IProcessProvider processProvider) + { + _runtimeInfo = runtimeInfo; + _processProvider = processProvider; + } + + public void Spin() + { + while (_runtimeInfo.IsRunning) + { + Thread.Sleep(1000); + } + + if (_runtimeInfo.RestartPending) + { + _processProvider.SpawnNewProcess(_runtimeInfo.ExecutingApplication, "--restart --nobrowser"); + } + } + } +} diff --git a/src/UI/Settings/General/GeneralViewTemplate.html b/src/UI/Settings/General/GeneralViewTemplate.html index 44d9e3d11..126283e4f 100644 --- a/src/UI/Settings/General/GeneralViewTemplate.html +++ b/src/UI/Settings/General/GeneralViewTemplate.html @@ -142,5 +142,28 @@ + + {{#if_mono}} +
+ + +
+
+ {{/if_mono}}
diff --git a/src/UpgradeLog.htm b/src/UpgradeLog.htm deleted file mode 100644 index 2732cdfdc8c588e9ef23d8894479e27f14c39aa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60810 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 M!-zpo!NQy7|Dbd882|tP diff --git a/src/UpgradeLog2.htm b/src/UpgradeLog2.htm deleted file mode 100644 index 2732cdfdc8c588e9ef23d8894479e27f14c39aa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60810 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 M!-zpo!NQy7|Dbd882|tP From 70266c921bd30e5790d1a046b7512337c6cc688a Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 10 Mar 2014 11:57:25 -0700 Subject: [PATCH 14/34] Update messenger instance if it was already created Fixed: UI notifications don't bounce around when there is more than one --- src/UI/Commands/CommandMessengerItemView.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/UI/Commands/CommandMessengerItemView.js b/src/UI/Commands/CommandMessengerItemView.js index d772943be..cc6d8a3f4 100644 --- a/src/UI/Commands/CommandMessengerItemView.js +++ b/src/UI/Commands/CommandMessengerItemView.js @@ -7,12 +7,10 @@ define( return Marionette.ItemView.extend({ - initialize: function () { this.listenTo(this.model, 'change', this.render); }, - render: function () { if (!this.model.get('message') || !this.model.get('sendUpdatesToClient')) { return; @@ -37,7 +35,13 @@ define( message.hideAfter = 0; } - Messenger.show(message); + if (this.messenger) { + this.messenger.update(message); + } + + else { + this.messenger = Messenger.show(message); + } console.log(message.message); } From db5baf70ea3907a57c3ad4b37f0eb093a78d55d3 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 10 Mar 2014 12:20:28 -0700 Subject: [PATCH 15/34] Don't clean common words from the start of the title Fixed: Do not treat similar titles as the exact same --- .../ParserTests/NormalizeTitleFixture.cs | 37 ++++++++++++++++--- .../ParserTests/ParserFixture.cs | 33 ----------------- src/NzbDrone.Core/Parser/Parser.cs | 2 +- 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs b/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs index 19c42dff4..c58170bc1 100644 --- a/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs @@ -15,8 +15,6 @@ namespace NzbDrone.Core.Test.ParserTests public class NormalizeTitleFixture : CoreTest { [TestCase("Conan", "conan")] - [TestCase("The Tonight Show With Jay Leno", "tonightshowwithjayleno")] - [TestCase("The.Daily.Show", "dailyshow")] [TestCase("Castle (2009)", "castle2009")] [TestCase("Parenthood.2010", "parenthood2010")] [TestCase("Law_and_Order_SVU", "lawordersvu")] @@ -51,9 +49,6 @@ namespace NzbDrone.Core.Test.ParserTests "word.{0}.word", "word {0} word", "word-{0}-word", - "{0}.word.word", - "{0}-word-word", - "{0} word word", "word.word.{0}", "word-word-{0}", "word-word {0}", @@ -64,7 +59,6 @@ namespace NzbDrone.Core.Test.ParserTests var dirty = String.Format(s, word); dirty.CleanSeriesTitle().Should().Be("wordword"); } - } [TestCase("the")] @@ -92,5 +86,36 @@ namespace NzbDrone.Core.Test.ParserTests } } + + [TestCase("The Office", "theoffice")] + [TestCase("The Tonight Show With Jay Leno", "thetonightshowwithjayleno")] + [TestCase("The.Daily.Show", "thedailyshow")] + public void should_not_remove_from_the_beginning_of_the_title(string parsedSeriesName, string seriesName) + { + var result = parsedSeriesName.CleanSeriesTitle(); + result.Should().Be(seriesName); + } + + [TestCase("the")] + [TestCase("and")] + [TestCase("or")] + [TestCase("a")] + [TestCase("an")] + [TestCase("of")] + public void should_not_clean_word_from_beginning_of_string(string word) + { + var dirtyFormat = new[] + { + "{0}.word.word", + "{0}-word-word", + "{0} word word" + }; + + foreach (var s in dirtyFormat) + { + var dirty = String.Format(s, word); + dirty.CleanSeriesTitle().Should().Be(word + "wordword"); + } + } } } diff --git a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs index 359699d13..6d6690996 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs @@ -23,39 +23,6 @@ namespace NzbDrone.Core.Test.ParserTests * Superman.-.The.Man.of.Steel.1994-05.33.hybrid.DreamGirl-Novus-HD */ - [TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "High School DxD", 7, 0, 0)] - [TestCase("[Chihiro]_Working!!_-_06_[848x480_H.264_AAC][859EEAFA]", "Working!!", 6, 0, 0)] - [TestCase("[Commie]_Senki_Zesshou_Symphogear_-_11_[65F220B4]", "Senki_Zesshou_Symphogear", 11, 0, 0)] - [TestCase("[Underwater]_Rinne_no_Lagrange_-_12_(720p)_[5C7BC4F9]", "Rinne_no_Lagrange", 12, 0, 0)] - [TestCase("[Commie]_Rinne_no_Lagrange_-_15_[E76552EA]", "Rinne_no_Lagrange", 15, 0, 0)] - [TestCase("[HorribleSubs]_Hunter_X_Hunter_-_33_[720p]", "Hunter_X_Hunter", 33, 0, 0)] - [TestCase("[HorribleSubs]_Fairy_Tail_-_145_[720p]", "Fairy_Tail", 145, 0, 0)] - [TestCase("[HorribleSubs] Tonari no Kaibutsu-kun - 13 [1080p].mkv", "Tonari no Kaibutsu-kun", 13, 0, 0)] - [TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", "Yes.Pretty.Cure.5.Go.Go!", 31, 0, 0)] - [TestCase("[K-F] One Piece 214", "One Piece", 214, 0, 0)] - [TestCase("[K-F] One Piece S10E14 214", "One Piece", 214, 10, 14)] - [TestCase("[K-F] One Piece 10x14 214", "One Piece", 214, 10, 14)] - [TestCase("[K-F] One Piece 214 10x14", "One Piece", 214, 10, 14)] -// [TestCase("One Piece S10E14 214", "One Piece", 214, 10, 14)] -// [TestCase("One Piece 10x14 214", "One Piece", 214, 10, 14)] -// [TestCase("One Piece 214 10x14", "One Piece", 214, 10, 14)] -// [TestCase("214 One Piece 10x14", "One Piece", 214, 10, 14)] - [TestCase("Bleach - 031 - The Resolution to Kill [Lunar].avi", "Bleach", 31, 0, 0)] - [TestCase("Bleach - 031 - The Resolution to Kill [Lunar]", "Bleach", 31, 0, 0)] - [TestCase("[ACX]Hack Sign 01 Role Play [Kosaka] [9C57891E].mkv", "Hack Sign", 1, 0, 0)] - [TestCase("[SFW-sage] Bakuman S3 - 12 [720p][D07C91FC]", "Bakuman S3", 12, 0, 0)] - [TestCase("ducktales_e66_time_is_money_part_one_marking_time", "DuckTales", 66, 0, 0)] - public void parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber) - { - var result = Parser.Parser.ParseTitle(postTitle); - result.Should().NotBeNull(); - result.AbsoluteEpisodeNumbers.First().Should().Be(absoluteEpisodeNumber); - result.SeasonNumber.Should().Be(seasonNumber); - result.EpisodeNumbers.FirstOrDefault().Should().Be(episodeNumber); - result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); - result.FullSeason.Should().BeFalse(); - } - [TestCase("Chuck - 4x05 - Title", "Chuck")] [TestCase("Law & Order - 4x05 - Title", "laworder")] [TestCase("Bad Format", "badformat")] diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index 4f1b52395..58ea810f5 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -100,7 +100,7 @@ namespace NzbDrone.Core.Parser RegexOptions.IgnoreCase | RegexOptions.Compiled) }; - private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(a|an|the|and|or|of)(?:\b|_))|\W|_", + private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?|\?|\*|\:|\|", From 9447ea6786f7c88ef40dd678efedccdb92a74c35 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 10 Mar 2014 12:24:32 -0700 Subject: [PATCH 16/34] Fixed broken tests --- src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs index 6d6690996..bfcbcb926 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs @@ -28,8 +28,8 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("Bad Format", "badformat")] [TestCase("Mad Men - Season 1 [Bluray720p]", "madmen")] [TestCase("Mad Men - Season 1 [Bluray1080p]", "madmen")] - [TestCase("The Daily Show With Jon Stewart -", "dailyshowwithjonstewart")] - [TestCase("The Venture Bros. (2004)", "venturebros2004")] + [TestCase("The Daily Show With Jon Stewart -", "thedailyshowwithjonstewart")] + [TestCase("The Venture Bros. (2004)", "theventurebros2004")] [TestCase("Castle (2011)", "castle2011")] [TestCase("Adventure Time S02 720p HDTV x264 CRON", "adventuretime")] [TestCase("Hawaii Five 0", "hawaiifive0")] From 0e5b1007339255c9d6dfd1647a42e0e990e95850 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 10 Mar 2014 20:54:43 -0700 Subject: [PATCH 17/34] Reverse proxy settings in UI --- src/UI/Settings/General/GeneralViewTemplate.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/UI/Settings/General/GeneralViewTemplate.html b/src/UI/Settings/General/GeneralViewTemplate.html index 126283e4f..6c5eee535 100644 --- a/src/UI/Settings/General/GeneralViewTemplate.html +++ b/src/UI/Settings/General/GeneralViewTemplate.html @@ -13,6 +13,18 @@ +
+ + +
+ + + + + +
+
+
From d7ca33ff048fbf6fd58c1038706cec49fc0f8732 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 10 Mar 2014 21:02:02 -0700 Subject: [PATCH 18/34] Fixed: UI notifications when using a reverse proxy --- src/UI/Mixins/backbone.signalr.mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UI/Mixins/backbone.signalr.mixin.js b/src/UI/Mixins/backbone.signalr.mixin.js index a29ed4882..72e0e7108 100644 --- a/src/UI/Mixins/backbone.signalr.mixin.js +++ b/src/UI/Mixins/backbone.signalr.mixin.js @@ -39,7 +39,7 @@ define( console.log(options.action + ': {0}}'.format(options.resource)); }; - collection.listenTo(vent, 'server:' + collection.url.replace('/api/', ''), processMessage); + collection.listenTo(vent, 'server:' + collection.url.split('/api/')[1], processMessage); return this; }, From 2d028d9bc71fa77401a5e732cd8cf9d8c154bb4a Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 11 Mar 2014 01:08:50 -0700 Subject: [PATCH 19/34] History check shouldn't die if download client is not configured. Do not log exceptron response when no errors are found --- .../Specifications/RssSync/HistorySpecification.cs | 4 +++- src/NzbDrone.Host/Owin/NlogTextWriter.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs index 1624c6296..17225a717 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs @@ -41,7 +41,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync return true; } - if (_downloadClientProvider.GetDownloadClient().GetType() == typeof (Sabnzbd)) + var downloadClient = _downloadClientProvider.GetDownloadClient(); + + if (downloadClient != null && downloadClient.GetType() == typeof (Sabnzbd)) { _logger.Trace("Performing history status check on report"); foreach (var episode in subject.Episodes) diff --git a/src/NzbDrone.Host/Owin/NlogTextWriter.cs b/src/NzbDrone.Host/Owin/NlogTextWriter.cs index 1bb580b91..cc1ba4627 100644 --- a/src/NzbDrone.Host/Owin/NlogTextWriter.cs +++ b/src/NzbDrone.Host/Owin/NlogTextWriter.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Host.Owin public override void Write(string value) { - if (value.ToLower().Contains("error") && !value.ToLower().Contains("sqlite")) + if (value.ToLower().Contains("error") && !(value.ToLower().Contains("sqlite") || value.ToLower().Contains("\"errors\":null"))) { _logger.Error(value); } From 11bc9467971d0423067bf665bb008047abecf127 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 11 Mar 2014 01:12:18 -0700 Subject: [PATCH 20/34] New: Jump to page on tables (click on page number) --- src/UI/.idea/jsLibraryMappings.xml | 7 ++- src/UI/.idea/jsLinters/jshint.xml | 4 +- src/UI/Content/Backgrid/paginator.less | 4 ++ src/UI/Handlebars/Helpers/Enumerable.js | 25 ++++++++++ .../backbone.marionette.templates.js | 1 + src/UI/Shared/Grid/JumpToPageTemplate.html | 9 ++++ src/UI/Shared/Grid/Pager.js | 48 +++++++++++++++++-- src/UI/Shared/Grid/PagerTemplate.html | 2 +- 8 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 src/UI/Handlebars/Helpers/Enumerable.js create mode 100644 src/UI/Shared/Grid/JumpToPageTemplate.html diff --git a/src/UI/.idea/jsLibraryMappings.xml b/src/UI/.idea/jsLibraryMappings.xml index f6e673adc..62c621f94 100644 --- a/src/UI/.idea/jsLibraryMappings.xml +++ b/src/UI/.idea/jsLibraryMappings.xml @@ -1,3 +1,8 @@ - + + + + + + diff --git a/src/UI/.idea/jsLinters/jshint.xml b/src/UI/.idea/jsLinters/jshint.xml index e85398a55..4e0df49ad 100644 --- a/src/UI/.idea/jsLinters/jshint.xml +++ b/src/UI/.idea/jsLinters/jshint.xml @@ -8,16 +8,16 @@
diff --git a/src/UI/Settings/settings.less b/src/UI/Settings/settings.less index 9f0ce6ac2..c46a629bc 100644 --- a/src/UI/Settings/settings.less +++ b/src/UI/Settings/settings.less @@ -93,3 +93,11 @@ li.save-and-add:hover { display: none; } } + +.api-key { + + input { + width : 280px; + cursor : text; + } +} diff --git a/src/UI/app.js b/src/UI/app.js index 2ab1cbdd1..85d8a566d 100644 --- a/src/UI/app.js +++ b/src/UI/app.js @@ -27,6 +27,7 @@ require.config({ 'jquery.dotdotdot' : 'JsLibraries/jquery.dotdotdot', 'messenger' : 'JsLibraries/messenger', 'jquery' : 'JsLibraries/jquery', + 'zero.clipboard' : 'JsLibraries/zero.clipboard', 'libs' : 'JsLibraries/', 'api': 'Require/require.api' From c2ab59f5c54e6ba086d04fbafd97ff947789e1e9 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 14 Mar 2014 02:41:56 -0700 Subject: [PATCH 28/34] New: Set scanning interval for Drone Factory --- .../Config/DownloadClientConfigResource.cs | 1 + .../Configuration/ConfigService.cs | 7 ++++++ .../Configuration/IConfigService.cs | 1 + src/NzbDrone.Core/Jobs/TaskManager.cs | 24 +++++++++++++++---- .../DownloadClientOptionsViewTemplate.html | 12 ++++++++++ 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs index f3fa14e8b..c6525577c 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs @@ -7,6 +7,7 @@ namespace NzbDrone.Api.Config { public String DownloadedEpisodesFolder { get; set; } public String DownloadClientWorkingFolders { get; set; } + public Int32 DownloadedEpisodesScanInterval { get; set; } public Boolean AutoRedownloadFailed { get; set; } public Boolean RemoveFailedDownloads { get; set; } diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 465b422b6..9626b969b 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -157,6 +157,13 @@ namespace NzbDrone.Core.Configuration set { SetValue("DownloadClientWorkingFolders", value); } } + public Int32 DownloadedEpisodesScanInterval + { + get { return GetValueInt("DownloadedEpisodesScanInterval", 1); } + + set { SetValue("DownloadedEpisodesScanInterval", value); } + } + public Boolean SetPermissionsLinux { get { return GetValueBoolean("SetPermissionsLinux", false); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 6540ebf45..9a513e75a 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -13,6 +13,7 @@ namespace NzbDrone.Core.Configuration //Download Client String DownloadedEpisodesFolder { get; set; } String DownloadClientWorkingFolders { get; set; } + Int32 DownloadedEpisodesScanInterval { get; set; } //Failed Download Handling (Download client) Boolean AutoRedownloadFailed { get; set; } diff --git a/src/NzbDrone.Core/Jobs/TaskManager.cs b/src/NzbDrone.Core/Jobs/TaskManager.cs index c9c29d904..65cc35f80 100644 --- a/src/NzbDrone.Core/Jobs/TaskManager.cs +++ b/src/NzbDrone.Core/Jobs/TaskManager.cs @@ -5,7 +5,6 @@ using NLog; using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.DataAugmentation.Scene; -using NzbDrone.Core.DataAugmentation.Xem; using NzbDrone.Core.Download; using NzbDrone.Core.HealthCheck; using NzbDrone.Core.Housekeeping; @@ -40,14 +39,15 @@ namespace NzbDrone.Core.Jobs public IList GetPending() { - return _scheduledTaskRepository.All().Where(c => c.LastExecution.AddMinutes(c.Interval) < DateTime.UtcNow).ToList(); + return _scheduledTaskRepository.All() + .Where(c => c.Interval > 0 && c.LastExecution.AddMinutes(c.Interval) < DateTime.UtcNow) + .ToList(); } public void Handle(ApplicationStartedEvent message) { var defaultTasks = new[] { - new ScheduledTask{ Interval = _configService.RssSyncInterval, TypeName = typeof(RssSyncCommand).FullName}, new ScheduledTask{ Interval = 1, TypeName = typeof(DownloadedEpisodesScanCommand).FullName}, new ScheduledTask{ Interval = 1, TypeName = typeof(TrackedCommandCleanupCommand).FullName}, new ScheduledTask{ Interval = 1, TypeName = typeof(CheckForFailedDownloadCommand).FullName}, @@ -57,6 +57,18 @@ namespace NzbDrone.Core.Jobs new ScheduledTask{ Interval = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName}, new ScheduledTask{ Interval = 12*60, TypeName = typeof(RefreshSeriesCommand).FullName}, new ScheduledTask{ Interval = 24*60, TypeName = typeof(HousekeepingCommand).FullName}, + + new ScheduledTask + { + Interval = _configService.RssSyncInterval, + TypeName = typeof(RssSyncCommand).FullName + }, + + new ScheduledTask + { + Interval = _configService.DownloadedEpisodesScanInterval, + TypeName = typeof(DownloadedEpisodesScanCommand).FullName + }, }; var currentTasks = _scheduledTaskRepository.All().ToList(); @@ -102,7 +114,11 @@ namespace NzbDrone.Core.Jobs { var rss = _scheduledTaskRepository.GetDefinition(typeof(RssSyncCommand)); rss.Interval = _configService.RssSyncInterval; - _scheduledTaskRepository.Update(rss); + + var downloadedEpisodes = _scheduledTaskRepository.GetDefinition(typeof(DownloadedEpisodesScanCommand)); + downloadedEpisodes.Interval = _configService.DownloadedEpisodesScanInterval; + + _scheduledTaskRepository.UpdateMany(new List{ rss, downloadedEpisodes }); } } } diff --git a/src/UI/Settings/DownloadClient/Options/DownloadClientOptionsViewTemplate.html b/src/UI/Settings/DownloadClient/Options/DownloadClientOptionsViewTemplate.html index 888161027..b6824fb6b 100644 --- a/src/UI/Settings/DownloadClient/Options/DownloadClientOptionsViewTemplate.html +++ b/src/UI/Settings/DownloadClient/Options/DownloadClientOptionsViewTemplate.html @@ -11,4 +11,16 @@ + +
+ + +
+ + + + + +
+
\ No newline at end of file From 01d3decf7e76f747ab4ff93e92e4b11d1c968436 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 14 Mar 2014 03:15:30 -0700 Subject: [PATCH 29/34] Added Mono version health check --- .../DiskProviderTests/FreeSpaceFixtureBase.cs | 2 +- .../EnsureTest/PathExtensionFixture.cs | 2 +- .../PathExtensionFixture.cs | 4 +- .../Checks/MonoVersionCheckFixture.cs | 66 +++++++++++++++++++ .../NotUnpackingSpecificationFixture.cs | 2 +- .../MediaFiles/MediaFileServiceTest.cs | 2 +- .../NzbDrone.Core.Test.csproj | 3 +- .../HealthCheck/Checks/MonoVersionnCheck.cs | 49 ++++++++++++++ src/NzbDrone.Core/NzbDrone.Core.csproj | 1 + .../DiskProviderTests/DiskProviderFixture.cs | 2 +- .../DiskProviderTests/FreeSpaceFixture.cs | 2 +- src/NzbDrone.Test.Common/TestBase.cs | 2 +- 12 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs diff --git a/src/NzbDrone.Common.Test/DiskProviderTests/FreeSpaceFixtureBase.cs b/src/NzbDrone.Common.Test/DiskProviderTests/FreeSpaceFixtureBase.cs index 4917c4457..f63942a11 100644 --- a/src/NzbDrone.Common.Test/DiskProviderTests/FreeSpaceFixtureBase.cs +++ b/src/NzbDrone.Common.Test/DiskProviderTests/FreeSpaceFixtureBase.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Common.Test.DiskProviderTests [Test] public void should_be_able_to_check_space_on_ramdrive() { - LinuxOnly(); + MonoOnly(); Subject.GetAvailableSpace("/run/").Should().NotBe(0); } diff --git a/src/NzbDrone.Common.Test/EnsureTest/PathExtensionFixture.cs b/src/NzbDrone.Common.Test/EnsureTest/PathExtensionFixture.cs index 04562a119..3388df9ad 100644 --- a/src/NzbDrone.Common.Test/EnsureTest/PathExtensionFixture.cs +++ b/src/NzbDrone.Common.Test/EnsureTest/PathExtensionFixture.cs @@ -19,7 +19,7 @@ namespace NzbDrone.Common.Test.EnsureTest [TestCase(@"/var/user/file with, comma.mkv")] public void EnsureLinuxPath(string path) { - LinuxOnly(); + MonoOnly(); Ensure.That(path, () => path).IsValidPath(); } } diff --git a/src/NzbDrone.Common.Test/PathExtensionFixture.cs b/src/NzbDrone.Common.Test/PathExtensionFixture.cs index fbc2fb6b6..8c75708e2 100644 --- a/src/NzbDrone.Common.Test/PathExtensionFixture.cs +++ b/src/NzbDrone.Common.Test/PathExtensionFixture.cs @@ -50,7 +50,7 @@ namespace NzbDrone.Common.Test [TestCase(@"//CAPITAL//lower// ", @"/CAPITAL/lower")] public void Clean_Path_Linux(string dirty, string clean) { - LinuxOnly(); + MonoOnly(); var result = dirty.CleanFilePath(); result.Should().Be(clean); @@ -139,7 +139,7 @@ namespace NzbDrone.Common.Test [Test] public void get_actual_casing_should_return_original_value_in_linux() { - LinuxOnly(); + MonoOnly(); var path = Directory.GetCurrentDirectory(); path.GetActualCasing().Should().Be(path); path.GetActualCasing().Should().Be(path); diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs new file mode 100644 index 000000000..02b06ad81 --- /dev/null +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common.Processes; +using NzbDrone.Core.HealthCheck.Checks; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.HealthCheck.Checks +{ + [TestFixture] + public class MonoVersionCheckFixture : CoreTest + { + [SetUp] + public void Setup() + { + MonoOnly(); + } + + private void GivenOutput(string version) + { + Mocker.GetMock() + .Setup(s => s.StartAndCapture("mono", "--version")) + .Returns(new ProcessOutput + { + Standard = new List + { + String.Format("Mono JIT compiler version {0} (Debian {0}-8)", version), + "Copyright (C) 2002-2011 Novell, Inc, Xamarin, Inc and Contributors. www.mono-project.com" + } + }); + } + + [Test] + public void should_return_warning_when_mono_3_0() + { + GivenOutput("3.0.0.1"); + + Subject.Check().ShouldBeWarning(); + } + + [Test] + public void should_return_warning_when_mono_2_10_8() + { + GivenOutput("2.10.8.1"); + + Subject.Check().ShouldBeWarning(); + } + + [Test] + public void should_return_null_when_mono_3_2() + { + GivenOutput("3.2.0.1"); + + Subject.Check().Should().BeNull(); + } + + [Test] + public void should_return_null_when_mono_4_0() + { + GivenOutput("4.0.0.0"); + + Subject.Check().Should().BeNull(); + } + } +} diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs index 0f4019163..155420917 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs @@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications [Test] public void should_return_false_if_unopacking_on_linux() { - LinuxOnly(); + MonoOnly(); GivenInWorkingFolder(); GivenLastWriteTimeUtc(DateTime.UtcNow.AddDays(-5)); diff --git a/src/NzbDrone.Core.Test/MediaFiles/MediaFileServiceTest.cs b/src/NzbDrone.Core.Test/MediaFiles/MediaFileServiceTest.cs index 2135e773a..ea567a509 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MediaFileServiceTest.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MediaFileServiceTest.cs @@ -108,7 +108,7 @@ namespace NzbDrone.Core.Test.MediaFiles [Test] public void filter_should_return_none_existing_files_not_ignoring_case() { - LinuxOnly(); + MonoOnly(); var files = new List() { diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index b21c4cfd2..dda23aeb2 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -125,10 +125,11 @@ + - + diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs new file mode 100644 index 000000000..867e9d458 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs @@ -0,0 +1,49 @@ +using System; +using System.Text.RegularExpressions; +using NLog; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Common.Processes; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + public class MonoVersionnCheck : IProvideHealthCheck + { + private readonly IProcessProvider _processProvider; + private readonly Logger _logger; + private static readonly Regex VersionRegex = new Regex(@"(?<=\W)(?\d+\.\d+\.\d+\.\d+)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public MonoVersionnCheck(IProcessProvider processProvider, Logger logger) + { + _processProvider = processProvider; + _logger = logger; + } + + public HealthCheck Check() + { + if (!OsInfo.IsMono) + { + return null; + } + + var output = _processProvider.StartAndCapture("mono", "--version"); + + foreach (var line in output.Standard) + { + var versionMatch = VersionRegex.Match(line); + + if (versionMatch.Success) + { + var version = new Version(versionMatch.Groups["version"].Value); + + if (version >= new Version(3, 2)) + { + _logger.Debug("mono version is 3.2 or better: {0}", version.ToString()); + return null; + } + } + } + + return new HealthCheck(HealthCheckResultType.Warning, "mono version is less than 3.2, upgrade for improved stability"); + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index c2cf3f68b..258c9d773 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -268,6 +268,7 @@ + diff --git a/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs b/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs index aac55c5df..dffd16153 100644 --- a/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs +++ b/src/NzbDrone.Mono.Test/DiskProviderTests/DiskProviderFixture.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Mono.Test.DiskProviderTests { public DiskProviderFixture() { - LinuxOnly(); + MonoOnly(); } } } diff --git a/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs b/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs index 247a0801d..109fb4825 100644 --- a/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs +++ b/src/NzbDrone.Mono.Test/DiskProviderTests/FreeSpaceFixture.cs @@ -8,7 +8,7 @@ namespace NzbDrone.Mono.Test.DiskProviderTests { public FreeSpaceFixture() { - LinuxOnly(); + MonoOnly(); } } } diff --git a/src/NzbDrone.Test.Common/TestBase.cs b/src/NzbDrone.Test.Common/TestBase.cs index c42fca8a9..5809a8816 100644 --- a/src/NzbDrone.Test.Common/TestBase.cs +++ b/src/NzbDrone.Test.Common/TestBase.cs @@ -131,7 +131,7 @@ namespace NzbDrone.Test.Common } - protected void LinuxOnly() + protected void MonoOnly() { if (!OsInfo.IsMono) { From eeac2aee891d1b571c4d23af06e6f3fc09813b00 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 14 Mar 2014 03:23:28 -0700 Subject: [PATCH 30/34] Fixed test reference --- .../HealthCheck/Checks/MonoVersionCheckFixture.cs | 2 +- .../Checks/{MonoVersionnCheck.cs => MonoVersionCheck.cs} | 4 ++-- src/NzbDrone.Core/NzbDrone.Core.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/NzbDrone.Core/HealthCheck/Checks/{MonoVersionnCheck.cs => MonoVersionCheck.cs} (91%) diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs index 02b06ad81..8a9ab0e73 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs @@ -9,7 +9,7 @@ using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.HealthCheck.Checks { [TestFixture] - public class MonoVersionCheckFixture : CoreTest + public class MonoVersionCheckFixture : CoreTest { [SetUp] public void Setup() diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs similarity index 91% rename from src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs rename to src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs index 867e9d458..be2caf75f 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionnCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs @@ -6,13 +6,13 @@ using NzbDrone.Common.Processes; namespace NzbDrone.Core.HealthCheck.Checks { - public class MonoVersionnCheck : IProvideHealthCheck + public class MonoVersionCheck : IProvideHealthCheck { private readonly IProcessProvider _processProvider; private readonly Logger _logger; private static readonly Regex VersionRegex = new Regex(@"(?<=\W)(?\d+\.\d+\.\d+\.\d+)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); - public MonoVersionnCheck(IProcessProvider processProvider, Logger logger) + public MonoVersionCheck(IProcessProvider processProvider, Logger logger) { _processProvider = processProvider; _logger = logger; diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 258c9d773..941d40815 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -268,7 +268,7 @@ - + From 088028b4261581a672bb0247a44c1a0966c8a710 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 14 Mar 2014 12:35:34 -0700 Subject: [PATCH 31/34] DB will log Info and above now (temp fix) --- src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs index 1ac73bd72..9f43eadbb 100644 --- a/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs +++ b/src/NzbDrone.Core/Instrumentation/DatabaseTarget.cs @@ -24,7 +24,7 @@ namespace NzbDrone.Core.Instrumentation { Layout = new SimpleLayout("${callsite:className=false:fileName=false:includeSourcePath=false:methodName=true}"); - Rule = new LoggingRule("*", LogLevel.Debug, this); + Rule = new LoggingRule("*", LogLevel.Info, this); LogManager.Configuration.AddTarget("DbLogger", this); LogManager.Configuration.LoggingRules.Add(Rule); From 7445adb4551b9735d593a905f36f089b8aea1730 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Fri, 14 Mar 2014 13:20:31 -0700 Subject: [PATCH 32/34] mono version check will support 3 digit versions --- .../Checks/MonoVersionCheckFixture.cs | 16 ++++++++++++++++ .../HealthCheck/Checks/MonoVersionCheck.cs | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs index 8a9ab0e73..5f968a90b 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/MonoVersionCheckFixture.cs @@ -62,5 +62,21 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks Subject.Check().Should().BeNull(); } + + [Test] + public void should_return_null_when_mono_3_2_7() + { + GivenOutput("3.2.7"); + + Subject.Check().Should().BeNull(); + } + + [Test] + public void should_return_null_when_mono_3_2_1() + { + GivenOutput("3.2.1"); + + Subject.Check().Should().BeNull(); + } } } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs index be2caf75f..ed24bf018 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/MonoVersionCheck.cs @@ -10,7 +10,7 @@ namespace NzbDrone.Core.HealthCheck.Checks { private readonly IProcessProvider _processProvider; private readonly Logger _logger; - private static readonly Regex VersionRegex = new Regex(@"(?<=\W)(?\d+\.\d+\.\d+\.\d+)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex VersionRegex = new Regex(@"(?<=\W)(?\d+\.\d+\.\d+(\.\d+)?)(?=\W)", RegexOptions.Compiled | RegexOptions.IgnoreCase); public MonoVersionCheck(IProcessProvider processProvider, Logger logger) { From 0a5ed41270fa4d0846f841f87fc17e1e8f950552 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 16 Mar 2014 22:31:27 -0700 Subject: [PATCH 33/34] Fixed: Don't blacklist nzbs due to disk space issues --- src/NzbDrone.Core/Download/FailedDownloadService.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs index c432eafeb..2805cc1c6 100644 --- a/src/NzbDrone.Core/Download/FailedDownloadService.cs +++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using NLog; using NzbDrone.Common; @@ -118,6 +119,14 @@ namespace NzbDrone.Core.Download continue; } + //TODO: Make this more configurable (ignore failure reasons) to support changes and other failures that should be ignored + if (failedLocal.Message.Equals("Unpacking failed, write error or disk is full?", + StringComparison.InvariantCultureIgnoreCase)) + { + _logger.Debug("Failed due to lack of disk space, do not blacklist"); + continue; + } + if (failedHistory.Any(h => failedLocal.Id.Equals(h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID)))) { _logger.Debug("Already added to history as failed"); From 87f591dfbd271f4805cf99d9d0defda21465bb24 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 16 Mar 2014 22:32:39 -0700 Subject: [PATCH 34/34] Fixed: nzb.su URL changed to api.nzb.su --- .../Download/FailedDownloadServiceFixture.cs | 17 +++++++++++++++++ .../Datastore/Migration/046_fix_nzb_su_url.cs | 16 ++++++++++++++++ src/NzbDrone.Core/NzbDrone.Core.csproj | 1 + 3 files changed, 34 insertions(+) create mode 100644 src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs diff --git a/src/NzbDrone.Core.Test/Download/FailedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/FailedDownloadServiceFixture.cs index bb91060ae..fc8bf395f 100644 --- a/src/NzbDrone.Core.Test/Download/FailedDownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/FailedDownloadServiceFixture.cs @@ -253,5 +253,22 @@ namespace NzbDrone.Core.Test.Download VerifyNoFailedDownloads(); } + + [Test] + public void should_not_process_if_failed_due_to_lack_of_disk_space() + { + var history = Builder.CreateListOfSize(1) + .Build() + .ToList(); + + GivenGrabbedHistory(history); + GivenFailedDownloadClientHistory(); + + _failed.First().Message = "Unpacking failed, write error or disk is full?"; + + Subject.Execute(new CheckForFailedDownloadCommand()); + + VerifyNoFailedDownloads(); + } } } diff --git a/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs b/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs new file mode 100644 index 000000000..6d5496c0a --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/046_fix_nzb_su_url.cs @@ -0,0 +1,16 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(46)] + public class fix_nzb_su_url : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Execute.Sql("UPDATE Indexers SET Settings = replace(Settings, '//nzb.su', '//api.nzb.su')" + + "WHERE Implementation = 'Newznab'" + + "AND Settings LIKE '%//nzb.su%'"); + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 941d40815..5f619fad6 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -191,6 +191,7 @@ Code +