diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 53632a51c..ee7506507 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -139,6 +139,7 @@
+
diff --git a/MediaBrowser.Controller/Persistence/IFileSortingRepository.cs b/MediaBrowser.Controller/Persistence/IFileSortingRepository.cs
new file mode 100644
index 000000000..117fd7c5c
--- /dev/null
+++ b/MediaBrowser.Controller/Persistence/IFileSortingRepository.cs
@@ -0,0 +1,25 @@
+using MediaBrowser.Model.FileSorting;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Persistence
+{
+ public interface IFileSortingRepository
+ {
+ ///
+ /// Saves the result.
+ ///
+ /// The result.
+ /// The cancellation token.
+ /// Task.
+ Task SaveResult(FileSortingResult result, CancellationToken cancellationToken);
+
+ ///
+ /// Gets the results.
+ ///
+ /// The query.
+ /// IEnumerable{FileSortingResult}.
+ IEnumerable GetResults(FileSortingResultQuery query);
+ }
+}
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 708573e8f..f588dde22 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -206,6 +206,12 @@
Extensions\ModelExtensions.cs
+
+ FileSorting\FileSortingResult.cs
+
+
+ FileSorting\FileSortingResultQuery.cs
+
Games\GameSystem.cs
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index 5fe9c4e5c..3015569e1 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -193,6 +193,12 @@
Extensions\ModelExtensions.cs
+
+ FileSorting\FileSortingResult.cs
+
+
+ FileSorting\FileSortingResultQuery.cs
+
Games\GameSystem.cs
diff --git a/MediaBrowser.Model/FileSorting/FileSortingResult.cs b/MediaBrowser.Model/FileSorting/FileSortingResult.cs
new file mode 100644
index 000000000..43c5e7ede
--- /dev/null
+++ b/MediaBrowser.Model/FileSorting/FileSortingResult.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace MediaBrowser.Model.FileSorting
+{
+ public class FileSortingResult
+ {
+ ///
+ /// Gets or sets the original path.
+ ///
+ /// The original path.
+ public string OriginalPath { get; set; }
+
+ ///
+ /// Gets or sets the target path.
+ ///
+ /// The target path.
+ public string TargetPath { get; set; }
+
+ ///
+ /// Gets or sets the date.
+ ///
+ /// The date.
+ public DateTime Date { get; set; }
+
+ ///
+ /// Gets or sets the error message.
+ ///
+ /// The error message.
+ public string ErrorMessage { get; set; }
+
+ ///
+ /// Gets or sets the status.
+ ///
+ /// The status.
+ public FileSortingStatus Status { get; set; }
+ }
+
+ public enum FileSortingStatus
+ {
+ Success,
+ Failure,
+ SkippedExisting,
+ SkippedTrial
+ }
+}
diff --git a/MediaBrowser.Model/FileSorting/FileSortingResultQuery.cs b/MediaBrowser.Model/FileSorting/FileSortingResultQuery.cs
new file mode 100644
index 000000000..7a83cad7b
--- /dev/null
+++ b/MediaBrowser.Model/FileSorting/FileSortingResultQuery.cs
@@ -0,0 +1,18 @@
+
+namespace MediaBrowser.Model.FileSorting
+{
+ public class FileSortingResultQuery
+ {
+ ///
+ /// Skips over a given number of items within the results. Use for paging.
+ ///
+ /// The start index.
+ public int? StartIndex { get; set; }
+
+ ///
+ /// The maximum number of items to return
+ ///
+ /// The limit.
+ public int? Limit { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 0eddcd7e7..490dd86d3 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -71,6 +71,8 @@
+
+
diff --git a/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs b/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs
index a9d7ada94..622546794 100644
--- a/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs
@@ -2,6 +2,7 @@
using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@@ -16,13 +17,15 @@ namespace MediaBrowser.Server.Implementations.FileSorting
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly IFileSystem _fileSystem;
+ private readonly IFileSortingRepository _iFileSortingRepository;
- public SortingScheduledTask(IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem)
+ public SortingScheduledTask(IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem, IFileSortingRepository iFileSortingRepository)
{
_config = config;
_logger = logger;
_libraryManager = libraryManager;
_fileSystem = fileSystem;
+ _iFileSortingRepository = iFileSortingRepository;
}
public string Name
@@ -42,12 +45,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting
public Task Execute(CancellationToken cancellationToken, IProgress progress)
{
- return Task.Run(() => SortFiles(cancellationToken, progress), cancellationToken);
- }
-
- private void SortFiles(CancellationToken cancellationToken, IProgress progress)
- {
- new TvFileSorter(_libraryManager, _logger, _fileSystem).Sort(_config.Configuration.FileSortingOptions, cancellationToken, progress);
+ return new TvFileSorter(_libraryManager, _logger, _fileSystem, _iFileSortingRepository).Sort(_config.Configuration.FileSortingOptions, cancellationToken, progress);
}
public IEnumerable GetDefaultTriggers()
diff --git a/MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs b/MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs
index cac05d426..679ab2c2d 100644
--- a/MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs
+++ b/MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs
@@ -1,10 +1,12 @@
using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.FileSorting;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@@ -12,6 +14,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.FileSorting
{
@@ -20,26 +23,29 @@ namespace MediaBrowser.Server.Implementations.FileSorting
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
+ private readonly IFileSortingRepository _iFileSortingRepository;
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public TvFileSorter(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
+
+ public TvFileSorter(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IFileSortingRepository iFileSortingRepository)
{
_libraryManager = libraryManager;
_logger = logger;
_fileSystem = fileSystem;
+ _iFileSortingRepository = iFileSortingRepository;
}
- public void Sort(FileSortingOptions options, CancellationToken cancellationToken, IProgress progress)
+ public async Task Sort(FileSortingOptions options, CancellationToken cancellationToken, IProgress progress)
{
var minFileBytes = options.MinFileSizeMb * 1024 * 1024;
- var eligibleFiles = options.TvWatchLocations.SelectMany(GetEligibleFiles)
+ var eligibleFiles = options.TvWatchLocations.SelectMany(GetFilesToSort)
+ .OrderBy(_fileSystem.GetCreationTimeUtc)
.Where(i => EntityResolutionHelper.IsVideoFile(i.FullName) && i.Length >= minFileBytes)
.ToList();
progress.Report(10);
-
+
if (eligibleFiles.Count > 0)
{
var allSeries = _libraryManager.RootFolder
@@ -48,16 +54,16 @@ namespace MediaBrowser.Server.Implementations.FileSorting
.ToList();
var numComplete = 0;
-
+
foreach (var file in eligibleFiles)
{
- SortFile(file.FullName, options, allSeries);
+ await SortFile(file.FullName, options, allSeries).ConfigureAwait(false);
numComplete++;
double percent = numComplete;
percent /= eligibleFiles.Count;
- progress.Report(100 * percent);
+ progress.Report(10 + (89 * percent));
}
}
@@ -83,7 +89,12 @@ namespace MediaBrowser.Server.Implementations.FileSorting
progress.Report(100);
}
- private IEnumerable GetEligibleFiles(string path)
+ ///
+ /// Gets the eligible files.
+ ///
+ /// The path.
+ /// IEnumerable{FileInfo}.
+ private IEnumerable GetFilesToSort(string path)
{
try
{
@@ -95,14 +106,26 @@ namespace MediaBrowser.Server.Implementations.FileSorting
{
_logger.ErrorException("Error getting files from {0}", ex, path);
- return new List();
+ return new List();
}
}
- private void SortFile(string path, FileSortingOptions options, IEnumerable allSeries)
+ ///
+ /// Sorts the file.
+ ///
+ /// The path.
+ /// The options.
+ /// All series.
+ private Task SortFile(string path, FileSortingOptions options, IEnumerable allSeries)
{
_logger.Info("Sorting file {0}", path);
+ var result = new FileSortingResult
+ {
+ Date = DateTime.UtcNow,
+ OriginalPath = path
+ };
+
var seriesName = TVUtils.GetSeriesNameFromEpisodeFile(path);
if (!string.IsNullOrEmpty(seriesName))
@@ -118,31 +141,55 @@ namespace MediaBrowser.Server.Implementations.FileSorting
{
_logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, season, episode);
- SortFile(path, seriesName, season.Value, episode.Value, options, allSeries);
+ SortFile(path, seriesName, season.Value, episode.Value, options, allSeries, result);
}
else
{
- _logger.Warn("Unable to determine episode number from {0}", path);
+ var msg = string.Format("Unable to determine episode number from {0}", path);
+ result.Status = FileSortingStatus.Failure;
+ result.ErrorMessage = msg;
+ _logger.Warn(msg);
}
}
else
{
- _logger.Warn("Unable to determine season number from {0}", path);
+ var msg = string.Format("Unable to determine season number from {0}", path);
+ result.Status = FileSortingStatus.Failure;
+ result.ErrorMessage = msg;
+ _logger.Warn(msg);
}
}
else
{
- _logger.Warn("Unable to determine series name from {0}", path);
+ var msg = string.Format("Unable to determine series name from {0}", path);
+ result.Status = FileSortingStatus.Failure;
+ result.ErrorMessage = msg;
+ _logger.Warn(msg);
}
+
+ return LogResult(result);
}
- private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, FileSortingOptions options, IEnumerable allSeries)
+ ///
+ /// Sorts the file.
+ ///
+ /// The path.
+ /// Name of the series.
+ /// The season number.
+ /// The episode number.
+ /// The options.
+ /// All series.
+ /// The result.
+ private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, FileSortingOptions options, IEnumerable allSeries, FileSortingResult result)
{
var series = GetMatchingSeries(seriesName, allSeries);
if (series == null)
{
- _logger.Warn("Unable to find series in library matching name {0}", seriesName);
+ var msg = string.Format("Unable to find series in library matching name {0}", seriesName);
+ result.Status = FileSortingStatus.Failure;
+ result.ErrorMessage = msg;
+ _logger.Warn(msg);
return;
}
@@ -153,13 +200,58 @@ namespace MediaBrowser.Server.Implementations.FileSorting
if (string.IsNullOrEmpty(newPath))
{
- _logger.Warn("Unable to sort {0} because target path could not be found.", path);
+ var msg = string.Format("Unable to sort {0} because target path could not be determined.", path);
+ result.Status = FileSortingStatus.Failure;
+ result.ErrorMessage = msg;
+ _logger.Warn(msg);
return;
}
_logger.Info("Sorting file {0} to new path {1}", path, newPath);
+ result.TargetPath = newPath;
+
+ if (options.EnableTrialMode)
+ {
+ result.Status = FileSortingStatus.SkippedTrial;
+ return;
+ }
+
+ if (!options.OverwriteExistingEpisodes && File.Exists(result.TargetPath))
+ {
+ result.Status = FileSortingStatus.SkippedExisting;
+ return;
+ }
+
+ PerformFileSorting(options, result);
}
+ ///
+ /// Performs the file sorting.
+ ///
+ /// The options.
+ /// The result.
+ private void PerformFileSorting(FileSortingOptions options, FileSortingResult result)
+ {
+ }
+
+ ///
+ /// Logs the result.
+ ///
+ /// The result.
+ /// Task.
+ private Task LogResult(FileSortingResult result)
+ {
+ return _iFileSortingRepository.SaveResult(result, CancellationToken.None);
+ }
+
+ ///
+ /// Gets the new path.
+ ///
+ /// The series.
+ /// The season number.
+ /// The episode number.
+ /// The options.
+ /// System.String.
private string GetNewPath(Series series, int seasonNumber, int episodeNumber, FileSortingOptions options)
{
var currentEpisodes = series.RecursiveChildren.OfType()
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 9c1be678d..95bafd1a3 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -179,6 +179,7 @@
+
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs
new file mode 100644
index 000000000..9f24d4d9c
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs
@@ -0,0 +1,21 @@
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.FileSorting;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+ public class SqliteFileSortingRepository : IFileSortingRepository
+ {
+ public Task SaveResult(FileSortingResult result, CancellationToken cancellationToken)
+ {
+ return Task.FromResult(true);
+ }
+
+ public IEnumerable GetResults(FileSortingResultQuery query)
+ {
+ return new List();
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 2858a781e..e02a26eb0 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -170,6 +170,7 @@ namespace MediaBrowser.ServerApplication
internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; }
internal IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
+ private IFileSortingRepository FileSortingRepository { get; set; }
///
/// Initializes a new instance of the class.
@@ -252,6 +253,9 @@ namespace MediaBrowser.ServerApplication
ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
RegisterSingleInstance(ItemRepository);
+ FileSortingRepository = new SqliteFileSortingRepository();
+ RegisterSingleInstance(FileSortingRepository);
+
UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository);
RegisterSingleInstance(UserManager);