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 | |
| parent | 5917d66172bb870102778222919575df6aa72dda (diff) | |
#680 - Support new episode file sorting
20 files changed, 352 insertions, 89 deletions
diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs index d057598e3..eae232f11 100644 --- a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs +++ b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs @@ -111,7 +111,9 @@ namespace MediaBrowser.Api.WebSocket { var line = await reader.ReadLineAsync().ConfigureAwait(false); - if (line.IndexOf(", Debug,", StringComparison.OrdinalIgnoreCase) == -1) + if (line.IndexOf(", Info,", StringComparison.OrdinalIgnoreCase) != -1 || + line.IndexOf(", Warn,", StringComparison.OrdinalIgnoreCase) != -1 || + line.IndexOf(", Error,", StringComparison.OrdinalIgnoreCase) != -1) { lines.Add(line); } diff --git a/MediaBrowser.Controller/FileOrganization/IFileOrganizationService.cs b/MediaBrowser.Controller/FileOrganization/IFileOrganizationService.cs new file mode 100644 index 000000000..993c04c28 --- /dev/null +++ b/MediaBrowser.Controller/FileOrganization/IFileOrganizationService.cs @@ -0,0 +1,30 @@ +using MediaBrowser.Model.FileOrganization; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.FileOrganization +{ + public interface IFileOrganizationService + { + /// <summary> + /// Processes the new files. + /// </summary> + void BeginProcessNewFiles(); + + /// <summary> + /// Saves the result. + /// </summary> + /// <param name="result">The result.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken); + + /// <summary> + /// Gets the results. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>IEnumerable{FileOrganizationResult}.</returns> + IEnumerable<FileOrganizationResult> GetResults(FileOrganizationResultQuery query); + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index ee7506507..56ac695a2 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -105,6 +105,7 @@ <Compile Include="Entities\LinkedChild.cs" /> <Compile Include="Entities\MusicVideo.cs" /> <Compile Include="Entities\IHasAwards.cs" /> + <Compile Include="FileOrganization\IFileOrganizationService.cs" /> <Compile Include="Library\ILibraryPostScanTask.cs" /> <Compile Include="Library\ILibraryPrescanTask.cs" /> <Compile Include="Library\IMetadataSaver.cs" /> @@ -139,7 +140,7 @@ <Compile Include="News\INewsService.cs" /> <Compile Include="Notifications\INotificationsRepository.cs" /> <Compile Include="Notifications\NotificationUpdateEventArgs.cs" /> - <Compile Include="Persistence\IFileSortingRepository.cs" /> + <Compile Include="Persistence\IFileOrganizationRepository.cs" /> <Compile Include="Persistence\MediaStreamQuery.cs" /> <Compile Include="Providers\IDynamicInfoProvider.cs" /> <Compile Include="Providers\IImageProvider.cs" /> diff --git a/MediaBrowser.Controller/Persistence/IFileSortingRepository.cs b/MediaBrowser.Controller/Persistence/IFileOrganizationRepository.cs index 117fd7c5c..9f5cc1579 100644 --- a/MediaBrowser.Controller/Persistence/IFileSortingRepository.cs +++ b/MediaBrowser.Controller/Persistence/IFileOrganizationRepository.cs @@ -1,11 +1,11 @@ -using MediaBrowser.Model.FileSorting; +using MediaBrowser.Model.FileOrganization; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Controller.Persistence { - public interface IFileSortingRepository + public interface IFileOrganizationRepository { /// <summary> /// Saves the result. @@ -13,13 +13,13 @@ namespace MediaBrowser.Controller.Persistence /// <param name="result">The result.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - Task SaveResult(FileSortingResult result, CancellationToken cancellationToken); + Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken); /// <summary> /// Gets the results. /// </summary> /// <param name="query">The query.</param> - /// <returns>IEnumerable{FileSortingResult}.</returns> - IEnumerable<FileSortingResult> GetResults(FileSortingResultQuery query); + /// <returns>IEnumerable{FileOrganizationResult}.</returns> + IEnumerable<FileOrganizationResult> GetResults(FileOrganizationResultQuery query); } } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index f588dde22..04f95c4ff 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -206,11 +206,11 @@ <Compile Include="..\MediaBrowser.Model\Extensions\ModelExtensions.cs"> <Link>Extensions\ModelExtensions.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\FileSorting\FileSortingResult.cs"> - <Link>FileSorting\FileSortingResult.cs</Link> + <Compile Include="..\MediaBrowser.Model\FileOrganization\FileOrganizationQuery.cs"> + <Link>FileOrganization\FileOrganizationQuery.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\FileSorting\FileSortingResultQuery.cs"> - <Link>FileSorting\FileSortingResultQuery.cs</Link> + <Compile Include="..\MediaBrowser.Model\FileOrganization\FileOrganizationResult.cs"> + <Link>FileOrganization\FileOrganizationResult.cs</Link> </Compile> <Compile Include="..\MediaBrowser.Model\Games\GameSystem.cs"> <Link>Games\GameSystem.cs</Link> @@ -272,6 +272,9 @@ <Compile Include="..\MediaBrowser.Model\Logging\LogSeverity.cs"> <Link>Logging\LogSeverity.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Logging\NullLogger.cs"> + <Link>Logging\NullLogger.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\MediaInfo\BlurayDiscInfo.cs"> <Link>MediaInfo\BlurayDiscInfo.cs</Link> </Compile> diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 3015569e1..bd411cce1 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -193,11 +193,11 @@ <Compile Include="..\MediaBrowser.Model\Extensions\ModelExtensions.cs"> <Link>Extensions\ModelExtensions.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\FileSorting\FileSortingResult.cs"> - <Link>FileSorting\FileSortingResult.cs</Link> + <Compile Include="..\MediaBrowser.Model\FileOrganization\FileOrganizationQuery.cs"> + <Link>FileOrganization\FileOrganizationQuery.cs</Link> </Compile> - <Compile Include="..\MediaBrowser.Model\FileSorting\FileSortingResultQuery.cs"> - <Link>FileSorting\FileSortingResultQuery.cs</Link> + <Compile Include="..\MediaBrowser.Model\FileOrganization\FileOrganizationResult.cs"> + <Link>FileOrganization\FileOrganizationResult.cs</Link> </Compile> <Compile Include="..\MediaBrowser.Model\Games\GameSystem.cs"> <Link>Games\GameSystem.cs</Link> @@ -259,6 +259,9 @@ <Compile Include="..\MediaBrowser.Model\Logging\LogSeverity.cs"> <Link>Logging\LogSeverity.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Logging\NullLogger.cs"> + <Link>Logging\NullLogger.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\MediaInfo\BlurayDiscInfo.cs"> <Link>MediaInfo\BlurayDiscInfo.cs</Link> </Compile> diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 9c13c8645..dd0c0ce3c 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -224,7 +224,7 @@ namespace MediaBrowser.Model.Configuration public bool EnableAutomaticRestart { get; set; } - public TvFileSortingOptions TvFileSortingOptions { get; set; } + public TvFileOrganizationOptions TvFileOrganizationOptions { get; set; } public LiveTvOptions LiveTvOptions { get; set; } /// <summary> @@ -293,7 +293,7 @@ namespace MediaBrowser.Model.Configuration LiveTvOptions = new LiveTvOptions(); - TvFileSortingOptions = new TvFileSortingOptions(); + TvFileOrganizationOptions = new TvFileOrganizationOptions(); } } @@ -316,7 +316,7 @@ namespace MediaBrowser.Model.Configuration public int? GuideDays { get; set; } } - public class TvFileSortingOptions + public class TvFileOrganizationOptions { public bool IsEnabled { get; set; } public int MinFileSizeMb { get; set; } @@ -326,6 +326,8 @@ namespace MediaBrowser.Model.Configuration public string SeasonFolderPattern { get; set; } public string SeasonZeroFolderName { get; set; } + + public string EpisodeNamePattern { get; set; } public bool OverwriteExistingEpisodes { get; set; } @@ -336,17 +338,15 @@ namespace MediaBrowser.Model.Configuration /// </summary> public bool EnableTrialMode { get; set; } - public TvFileSortingOptions() + public TvFileOrganizationOptions() { MinFileSizeMb = 50; - LeftOverFileExtensionsToDelete = new[] { - ".nfo", - ".txt" - }; + LeftOverFileExtensionsToDelete = new string[] {}; WatchLocations = new string[] { }; + EpisodeNamePattern = "%sn - %sx%0e - %en.%ext"; SeasonFolderPattern = "Season %s"; SeasonZeroFolderName = "Season 0"; diff --git a/MediaBrowser.Model/FileSorting/FileSortingResultQuery.cs b/MediaBrowser.Model/FileOrganization/FileOrganizationQuery.cs index 7a83cad7b..18287534e 100644 --- a/MediaBrowser.Model/FileSorting/FileSortingResultQuery.cs +++ b/MediaBrowser.Model/FileOrganization/FileOrganizationQuery.cs @@ -1,7 +1,7 @@ -namespace MediaBrowser.Model.FileSorting +namespace MediaBrowser.Model.FileOrganization { - public class FileSortingResultQuery + public class FileOrganizationResultQuery { /// <summary> /// Skips over a given number of items within the results. Use for paging. diff --git a/MediaBrowser.Model/FileSorting/FileSortingResult.cs b/MediaBrowser.Model/FileOrganization/FileOrganizationResult.cs index 43c5e7ede..505f0e2da 100644 --- a/MediaBrowser.Model/FileSorting/FileSortingResult.cs +++ b/MediaBrowser.Model/FileOrganization/FileOrganizationResult.cs @@ -1,8 +1,8 @@ using System; -namespace MediaBrowser.Model.FileSorting +namespace MediaBrowser.Model.FileOrganization { - public class FileSortingResult + public class FileOrganizationResult { /// <summary> /// Gets or sets the original path. diff --git a/MediaBrowser.Model/Logging/NullLogger.cs b/MediaBrowser.Model/Logging/NullLogger.cs new file mode 100644 index 000000000..d211d2567 --- /dev/null +++ b/MediaBrowser.Model/Logging/NullLogger.cs @@ -0,0 +1,44 @@ +using System; +using System.Text; + +namespace MediaBrowser.Model.Logging +{ + public class NullLogger : ILogger + { + public void Info(string message, params object[] paramList) + { + } + + public void Error(string message, params object[] paramList) + { + } + + public void Warn(string message, params object[] paramList) + { + } + + public void Debug(string message, params object[] paramList) + { + } + + public void Fatal(string message, params object[] paramList) + { + } + + public void FatalException(string message, Exception exception, params object[] paramList) + { + } + + public void Log(LogSeverity severity, string message, params object[] paramList) + { + } + + public void ErrorException(string message, Exception exception, params object[] paramList) + { + } + + public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent) + { + } + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 490dd86d3..1e9b57971 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -71,8 +71,8 @@ <Compile Include="Dto\ItemCounts.cs" /> <Compile Include="Dto\ItemIndex.cs" /> <Compile Include="Entities\PackageReviewInfo.cs" /> - <Compile Include="FileSorting\FileSortingResult.cs" /> - <Compile Include="FileSorting\FileSortingResultQuery.cs" /> + <Compile Include="FileOrganization\FileOrganizationResult.cs" /> + <Compile Include="FileOrganization\FileOrganizationQuery.cs" /> <Compile Include="LiveTv\ChannelInfoDto.cs" /> <Compile Include="LiveTv\ChannelQuery.cs" /> <Compile Include="LiveTv\ProgramInfoDto.cs" /> @@ -82,6 +82,7 @@ <Compile Include="LiveTv\RecordingStatus.cs" /> <Compile Include="LiveTv\SeriesTimerInfoDto.cs" /> <Compile Include="LiveTv\TimerInfoDto.cs" /> + <Compile Include="Logging\NullLogger.cs" /> <Compile Include="News\NewsItem.cs" /> <Compile Include="Providers\ImageProviderInfo.cs" /> <Compile Include="Providers\RemoteImageInfo.cs" /> 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>(); - } - } -} diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index e02a26eb0..c1d36c79a 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -13,6 +13,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.FileOrganization; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; @@ -38,6 +39,7 @@ using MediaBrowser.Server.Implementations.Configuration; using MediaBrowser.Server.Implementations.Drawing; using MediaBrowser.Server.Implementations.Dto; using MediaBrowser.Server.Implementations.EntryPoints; +using MediaBrowser.Server.Implementations.FileOrganization; using MediaBrowser.Server.Implementations.HttpServer; using MediaBrowser.Server.Implementations.IO; using MediaBrowser.Server.Implementations.Library; @@ -170,7 +172,7 @@ namespace MediaBrowser.ServerApplication internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; } internal IItemRepository ItemRepository { get; set; } private INotificationsRepository NotificationsRepository { get; set; } - private IFileSortingRepository FileSortingRepository { get; set; } + private IFileOrganizationRepository FileOrganizationRepository { get; set; } /// <summary> /// Initializes a new instance of the <see cref="ApplicationHost"/> class. @@ -253,8 +255,8 @@ namespace MediaBrowser.ServerApplication ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager); RegisterSingleInstance(ItemRepository); - FileSortingRepository = new SqliteFileSortingRepository(); - RegisterSingleInstance(FileSortingRepository); + FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false); + RegisterSingleInstance(FileOrganizationRepository); UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository); RegisterSingleInstance(UserManager); @@ -292,6 +294,9 @@ namespace MediaBrowser.ServerApplication var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer); RegisterSingleInstance<INewsService>(newsService); + var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository); + RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService); + progress.Report(15); var innerProgress = new ActionableProgress<double>(); @@ -366,6 +371,19 @@ namespace MediaBrowser.ServerApplication } /// <summary> + /// Gets the file organization repository. + /// </summary> + /// <returns>Task{IUserRepository}.</returns> + private async Task<IFileOrganizationRepository> GetFileOrganizationRepository() + { + var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths); + + await repo.Initialize().ConfigureAwait(false); + + return repo; + } + + /// <summary> /// Configures the repositories. /// </summary> /// <returns>Task.</returns> diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index a02da385d..83043dd43 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -494,6 +494,7 @@ namespace MediaBrowser.WebDashboard.Api "itemgallery.js", "itemlistpage.js", "librarysettings.js", + "libraryfileorganizer.js", "livetvchannel.js", "livetvchannels.js", "livetvguide.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 2066c6cb9..d3b0285d0 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -169,6 +169,9 @@ <Content Include="dashboard-ui\encodingsettings.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\libraryfileorganizer.html">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\livetvchannel.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -418,6 +421,9 @@ <Content Include="dashboard-ui\scripts\encodingsettings.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\scripts\libraryfileorganizer.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\scripts\librarymenu.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
|
