diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-20 11:09:53 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-20 11:09:53 -0500 |
| commit | c798529caca49ef8c323c0e003dd9f4ba0394b5a (patch) | |
| tree | 635794b946774e151976f5a36327ecd10a88caf7 /MediaBrowser.Server.Implementations | |
| parent | 5917d66172bb870102778222919575df6aa72dda (diff) | |
#680 - Support new episode file sorting
Diffstat (limited to 'MediaBrowser.Server.Implementations')
| -rw-r--r-- | MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs | 38 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs (renamed from MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs) | 20 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/FileOrganization/TvFileSorter.cs (renamed from MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs) | 64 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj | 7 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs | 118 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs | 21 |
6 files changed, 211 insertions, 57 deletions
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs new file mode 100644 index 000000000..9d8236bde --- /dev/null +++ b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs @@ -0,0 +1,38 @@ +using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.FileOrganization; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.FileOrganization; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.FileOrganization +{ + public class FileOrganizationService : IFileOrganizationService + { + private readonly ITaskManager _taskManager; + private readonly IFileOrganizationRepository _repo; + + public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo) + { + _taskManager = taskManager; + _repo = repo; + } + + public void BeginProcessNewFiles() + { + _taskManager.CancelIfRunningAndQueue<OrganizerScheduledTask>(); + } + + + public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken) + { + return _repo.SaveResult(result, cancellationToken); + } + + public IEnumerable<FileOrganizationResult> GetResults(FileOrganizationResultQuery query) + { + return _repo.GetResults(query); + } + } +} diff --git a/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs index 85d172d36..5c5a83cb6 100644 --- a/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs @@ -1,25 +1,25 @@ using MediaBrowser.Common.IO; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.FileOrganization; using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.Implementations.FileSorting +namespace MediaBrowser.Server.Implementations.FileOrganization { - public class SortingScheduledTask : IScheduledTask, IConfigurableScheduledTask + public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask { private readonly IServerConfigurationManager _config; private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IFileSystem _fileSystem; - private readonly IFileSortingRepository _iFileSortingRepository; + private readonly IFileOrganizationService _iFileSortingRepository; - public SortingScheduledTask(IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem, IFileSortingRepository iFileSortingRepository) + public OrganizerScheduledTask(IServerConfigurationManager config, ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem, IFileOrganizationService iFileSortingRepository) { _config = config; _logger = logger; @@ -30,12 +30,12 @@ namespace MediaBrowser.Server.Implementations.FileSorting public string Name { - get { return "Sort new files"; } + get { return "Organize new media files"; } } public string Description { - get { return "Processes new files available in the configured sorting location."; } + get { return "Processes new files available in the configured watch folder."; } } public string Category @@ -45,7 +45,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { - return new TvFileSorter(_libraryManager, _logger, _fileSystem, _iFileSortingRepository).Sort(_config.Configuration.TvFileSortingOptions, cancellationToken, progress); + return new TvFileSorter(_libraryManager, _logger, _fileSystem, _iFileSortingRepository).Sort(_config.Configuration.TvFileOrganizationOptions, cancellationToken, progress); } public IEnumerable<ITaskTrigger> GetDefaultTriggers() @@ -58,12 +58,12 @@ namespace MediaBrowser.Server.Implementations.FileSorting public bool IsHidden { - get { return !_config.Configuration.TvFileSortingOptions.IsEnabled; } + get { return !_config.Configuration.TvFileOrganizationOptions.IsEnabled; } } public bool IsEnabled { - get { return _config.Configuration.TvFileSortingOptions.IsEnabled; } + get { return _config.Configuration.TvFileOrganizationOptions.IsEnabled; } } } } diff --git a/MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFileSorter.cs index 093a1dba6..24e2c094b 100644 --- a/MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFileSorter.cs @@ -1,12 +1,12 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.FileOrganization; 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.FileOrganization; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -16,18 +16,18 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace MediaBrowser.Server.Implementations.FileSorting +namespace MediaBrowser.Server.Implementations.FileOrganization { public class TvFileSorter { private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IFileSystem _fileSystem; - private readonly IFileSortingRepository _iFileSortingRepository; + private readonly IFileOrganizationService _iFileSortingRepository; private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public TvFileSorter(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IFileSortingRepository iFileSortingRepository) + public TvFileSorter(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IFileOrganizationService iFileSortingRepository) { _libraryManager = libraryManager; _logger = logger; @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting _iFileSortingRepository = iFileSortingRepository; } - public async Task Sort(TvFileSortingOptions options, CancellationToken cancellationToken, IProgress<double> progress) + public async Task Sort(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress<double> progress) { var minFileBytes = options.MinFileSizeMb * 1024 * 1024; @@ -118,11 +118,11 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// <param name="path">The path.</param> /// <param name="options">The options.</param> /// <param name="allSeries">All series.</param> - private Task SortFile(string path, TvFileSortingOptions options, IEnumerable<Series> allSeries) + private Task SortFile(string path, TvFileOrganizationOptions options, IEnumerable<Series> allSeries) { _logger.Info("Sorting file {0}", path); - var result = new FileSortingResult + var result = new FileOrganizationResult { Date = DateTime.UtcNow, OriginalPath = path @@ -182,7 +182,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// <param name="options">The options.</param> /// <param name="allSeries">All series.</param> /// <param name="result">The result.</param> - private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, TvFileSortingOptions options, IEnumerable<Series> allSeries, FileSortingResult result) + private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, TvFileOrganizationOptions options, IEnumerable<Series> allSeries, FileOrganizationResult result) { var series = GetMatchingSeries(seriesName, allSeries); @@ -198,7 +198,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting _logger.Info("Sorting file {0} into series {1}", path, series.Path); // Proceed to sort the file - var newPath = GetNewPath(series, seasonNumber, episodeNumber, options); + var newPath = GetNewPath(path, series, seasonNumber, episodeNumber, options); if (string.IsNullOrEmpty(newPath)) { @@ -234,7 +234,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// <param name="options">The options.</param> /// <param name="result">The result.</param> /// <param name="copy">if set to <c>true</c> [copy].</param> - private void PerformFileSorting(TvFileSortingOptions options, FileSortingResult result, bool copy) + private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result, bool copy) { try { @@ -253,7 +253,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting result.Status = FileSortingStatus.Failure; result.ErrorMessage = errorMsg; _logger.ErrorException(errorMsg, ex); - return; + return; } if (copy) @@ -274,7 +274,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// </summary> /// <param name="result">The result.</param> /// <returns>Task.</returns> - private Task LogResult(FileSortingResult result) + private Task LogResult(FileOrganizationResult result) { return _iFileSortingRepository.SaveResult(result, CancellationToken.None); } @@ -282,12 +282,13 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// <summary> /// Gets the new path. /// </summary> + /// <param name="sourcePath">The source path.</param> /// <param name="series">The series.</param> /// <param name="seasonNumber">The season number.</param> /// <param name="episodeNumber">The episode number.</param> /// <param name="options">The options.</param> /// <returns>System.String.</returns> - private string GetNewPath(Series series, int seasonNumber, int episodeNumber, TvFileSortingOptions options) + private string GetNewPath(string sourcePath, Series series, int seasonNumber, int episodeNumber, TvFileOrganizationOptions options) { var currentEpisodes = series.RecursiveChildren.OfType<Episode>() .Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value == episodeNumber && i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber) @@ -309,13 +310,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting var episode = currentEpisodes.First(); - var episodeFileName = string.Format("{0} - {1}x{2} - {3}", - - _fileSystem.GetValidFilename(series.Name), - seasonNumber.ToString(UsCulture), - episodeNumber.ToString("00", UsCulture), - _fileSystem.GetValidFilename(episode.Name) - ); + var episodeFileName = GetEpisodeFileName(sourcePath, series.Name, seasonNumber, episodeNumber, episode.Name, options); newPath = Path.Combine(newPath, episodeFileName); } @@ -323,6 +318,28 @@ namespace MediaBrowser.Server.Implementations.FileSorting return newPath; } + private string GetEpisodeFileName(string sourcePath, string seriesName, int seasonNumber, int episodeNumber, string episodeTitle, TvFileOrganizationOptions options) + { + seriesName = _fileSystem.GetValidFilename(seriesName); + episodeTitle = _fileSystem.GetValidFilename(episodeTitle); + + var sourceExtension = (Path.GetExtension(sourcePath) ?? string.Empty).TrimStart('.'); + + return options.EpisodeNamePattern.Replace("%sn", seriesName) + .Replace("%s.n", seriesName.Replace(" ", ".")) + .Replace("%s_n", seriesName.Replace(" ", "_")) + .Replace("%s", seasonNumber.ToString(UsCulture)) + .Replace("%0s", seasonNumber.ToString("00", UsCulture)) + .Replace("%00s", seasonNumber.ToString("000", UsCulture)) + .Replace("%ext", sourceExtension) + .Replace("%en", episodeTitle) + .Replace("%e.n", episodeTitle.Replace(" ", ".")) + .Replace("%e_n", episodeTitle.Replace(" ", "_")) + .Replace("%e", episodeNumber.ToString(UsCulture)) + .Replace("%0e", episodeNumber.ToString("00", UsCulture)) + .Replace("%00e", episodeNumber.ToString("000", UsCulture)); + } + /// <summary> /// Gets the season folder path. /// </summary> @@ -330,7 +347,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// <param name="seasonNumber">The season number.</param> /// <param name="options">The options.</param> /// <returns>System.String.</returns> - private string GetSeasonFolderPath(Series series, int seasonNumber, TvFileSortingOptions options) + private string GetSeasonFolderPath(Series series, int seasonNumber, TvFileOrganizationOptions options) { // If there's already a season folder, use that var season = series @@ -386,7 +403,8 @@ namespace MediaBrowser.Server.Implementations.FileSorting { var score = 0; - // TODO: Improve this + // TODO: Improve this - should ignore spaces, periods, underscores, most likely all symbols and + // possibly remove sorting words like "the", "and", etc. if (string.Equals(sortedName, series.Name, StringComparison.OrdinalIgnoreCase)) { score++; diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 95bafd1a3..349d93d83 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -117,11 +117,12 @@ <Compile Include="EntryPoints\Notifications\RemoteNotifications.cs" /> <Compile Include="EntryPoints\Notifications\WebSocketNotifier.cs" /> <Compile Include="EntryPoints\RefreshUsersMetadata.cs" /> - <Compile Include="FileSorting\TvFileSorter.cs" /> + <Compile Include="FileOrganization\FileOrganizationService.cs" /> + <Compile Include="FileOrganization\TvFileSorter.cs" /> <Compile Include="EntryPoints\UdpServerEntryPoint.cs" /> <Compile Include="EntryPoints\ServerEventNotifier.cs" /> <Compile Include="EntryPoints\UserDataChangeNotifier.cs" /> - <Compile Include="FileSorting\SortingScheduledTask.cs" /> + <Compile Include="FileOrganization\OrganizerScheduledTask.cs" /> <Compile Include="HttpServer\ContainerAdapter.cs" /> <Compile Include="HttpServer\HttpListenerHost.cs" /> <Compile Include="HttpServer\HttpResultFactory.cs" /> @@ -179,7 +180,7 @@ <Compile Include="News\NewsService.cs" /> <Compile Include="Persistence\SqliteChapterRepository.cs" /> <Compile Include="Persistence\SqliteExtensions.cs" /> - <Compile Include="Persistence\SqliteFileSortingRepository.cs" /> + <Compile Include="Persistence\SqliteFileOrganizationRepository.cs" /> <Compile Include="Persistence\SqliteMediaStreamsRepository.cs" /> <Compile Include="Persistence\SqliteNotificationsRepository.cs" /> <Compile Include="Persistence\SqliteProviderInfoRepository.cs" /> diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs new file mode 100644 index 000000000..a95f84f06 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs @@ -0,0 +1,118 @@ +using MediaBrowser.Controller; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.FileOrganization; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Persistence +{ + public class SqliteFileOrganizationRepository : IFileOrganizationRepository + { + private IDbConnection _connection; + + private readonly ILogger _logger; + + private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); + private SqliteShrinkMemoryTimer _shrinkMemoryTimer; + private readonly IServerApplicationPaths _appPaths; + + public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) + { + _appPaths = appPaths; + + _logger = logManager.GetLogger(GetType().Name); + } + + /// <summary> + /// Opens the connection to the database + /// </summary> + /// <returns>Task.</returns> + public async Task Initialize() + { + var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db"); + + _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); + + string[] queries = { + + //pragmas + "pragma temp_store = memory", + + "pragma shrink_memory" + }; + + _connection.RunQueries(queries, _logger); + + PrepareStatements(); + + _shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger); + } + + private void PrepareStatements() + { + } + + public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public IEnumerable<FileOrganizationResult> GetResults(FileOrganizationResultQuery query) + { + return new List<FileOrganizationResult>(); + } + + /// <summary> + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// </summary> + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private readonly object _disposeLock = new object(); + + /// <summary> + /// Releases unmanaged and - optionally - managed resources. + /// </summary> + /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + try + { + lock (_disposeLock) + { + if (_shrinkMemoryTimer != null) + { + _shrinkMemoryTimer.Dispose(); + _shrinkMemoryTimer = null; + } + + if (_connection != null) + { + if (_connection.IsOpen()) + { + _connection.Close(); + } + + _connection.Dispose(); + _connection = null; + } + } + } + catch (Exception ex) + { + _logger.ErrorException("Error disposing database", ex); + } + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs deleted file mode 100644 index 9f24d4d9c..000000000 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileSortingRepository.cs +++ /dev/null @@ -1,21 +0,0 @@ -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<FileSortingResult> GetResults(FileSortingResultQuery query) - { - return new List<FileSortingResult>(); - } - } -} |
