diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs index d057598e3e..eae232f110 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 0000000000..993c04c281 --- /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 + { + /// + /// Processes the new files. + /// + void BeginProcessNewFiles(); + + /// + /// Saves the result. + /// + /// The result. + /// The cancellation token. + /// Task. + Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken); + + /// + /// Gets the results. + /// + /// The query. + /// IEnumerable{FileOrganizationResult}. + IEnumerable GetResults(FileOrganizationResultQuery query); + } +} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index ee75065072..56ac695a2d 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -105,6 +105,7 @@ + @@ -139,7 +140,7 @@ - + diff --git a/MediaBrowser.Controller/Persistence/IFileSortingRepository.cs b/MediaBrowser.Controller/Persistence/IFileOrganizationRepository.cs similarity index 59% rename from MediaBrowser.Controller/Persistence/IFileSortingRepository.cs rename to MediaBrowser.Controller/Persistence/IFileOrganizationRepository.cs index 117fd7c5cd..9f5cc1579a 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 { /// /// Saves the result. @@ -13,13 +13,13 @@ namespace MediaBrowser.Controller.Persistence /// The result. /// The cancellation token. /// Task. - Task SaveResult(FileSortingResult result, CancellationToken cancellationToken); + Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken); /// /// Gets the results. /// /// The query. - /// IEnumerable{FileSortingResult}. - IEnumerable GetResults(FileSortingResultQuery query); + /// IEnumerable{FileOrganizationResult}. + IEnumerable GetResults(FileOrganizationResultQuery query); } } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index f588dde228..04f95c4ffd 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -206,11 +206,11 @@ Extensions\ModelExtensions.cs - - FileSorting\FileSortingResult.cs + + FileOrganization\FileOrganizationQuery.cs - - FileSorting\FileSortingResultQuery.cs + + FileOrganization\FileOrganizationResult.cs Games\GameSystem.cs @@ -272,6 +272,9 @@ Logging\LogSeverity.cs + + Logging\NullLogger.cs + MediaInfo\BlurayDiscInfo.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 3015569e14..bd411cce1c 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -193,11 +193,11 @@ Extensions\ModelExtensions.cs - - FileSorting\FileSortingResult.cs + + FileOrganization\FileOrganizationQuery.cs - - FileSorting\FileSortingResultQuery.cs + + FileOrganization\FileOrganizationResult.cs Games\GameSystem.cs @@ -259,6 +259,9 @@ Logging\LogSeverity.cs + + Logging\NullLogger.cs + MediaInfo\BlurayDiscInfo.cs diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 9c13c86457..dd0c0ce3ca 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; } /// @@ -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 /// 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 similarity index 81% rename from MediaBrowser.Model/FileSorting/FileSortingResultQuery.cs rename to MediaBrowser.Model/FileOrganization/FileOrganizationQuery.cs index 7a83cad7b0..18287534ea 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 { /// /// 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 similarity index 92% rename from MediaBrowser.Model/FileSorting/FileSortingResult.cs rename to MediaBrowser.Model/FileOrganization/FileOrganizationResult.cs index 43c5e7edee..505f0e2da5 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 { /// /// 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 0000000000..d211d2567d --- /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 490dd86d36..1e9b579716 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -71,8 +71,8 @@ - - + + @@ -82,6 +82,7 @@ + diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs new file mode 100644 index 0000000000..9d8236bde1 --- /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(); + } + + + public Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken) + { + return _repo.SaveResult(result, cancellationToken); + } + + public IEnumerable GetResults(FileOrganizationResultQuery query) + { + return _repo.GetResults(query); + } + } +} diff --git a/MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs similarity index 67% rename from MediaBrowser.Server.Implementations/FileSorting/SortingScheduledTask.cs rename to MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs index 85d172d361..5c5a83cb6d 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 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 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 similarity index 84% rename from MediaBrowser.Server.Implementations/FileSorting/TvFileSorter.cs rename to MediaBrowser.Server.Implementations/FileOrganization/TvFileSorter.cs index 093a1dba66..24e2c094b8 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 progress) + public async Task Sort(TvFileOrganizationOptions options, CancellationToken cancellationToken, IProgress progress) { var minFileBytes = options.MinFileSizeMb * 1024 * 1024; @@ -118,11 +118,11 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// The path. /// The options. /// All series. - private Task SortFile(string path, TvFileSortingOptions options, IEnumerable allSeries) + private Task SortFile(string path, TvFileOrganizationOptions options, IEnumerable 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 /// The options. /// All series. /// The result. - private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, TvFileSortingOptions options, IEnumerable allSeries, FileSortingResult result) + private void SortFile(string path, string seriesName, int seasonNumber, int episodeNumber, TvFileOrganizationOptions options, IEnumerable 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 /// The options. /// The result. /// if set to true [copy]. - 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 /// /// The result. /// Task. - 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 /// /// Gets the new path. /// + /// The source path. /// The series. /// The season number. /// The episode number. /// The options. /// System.String. - 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() .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)); + } + /// /// Gets the season folder path. /// @@ -330,7 +347,7 @@ namespace MediaBrowser.Server.Implementations.FileSorting /// The season number. /// The options. /// System.String. - 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 95bafd1a30..349d93d831 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -117,11 +117,12 @@ - + + - + @@ -179,7 +180,7 @@ - + diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs new file mode 100644 index 0000000000..a95f84f067 --- /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); + } + + /// + /// Opens the connection to the database + /// + /// Task. + 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 GetResults(FileOrganizationResultQuery query) + { + return new List(); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private readonly object _disposeLock = new object(); + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + 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 9f24d4d9ce..0000000000 --- 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 GetResults(FileSortingResultQuery query) - { - return new List(); - } - } -} diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index e02a26eb00..c1d36c79a2 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; } /// /// Initializes a new instance of the 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(newsService); + var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository); + RegisterSingleInstance(fileOrganizationService); + progress.Report(15); var innerProgress = new ActionableProgress(); @@ -365,6 +370,19 @@ namespace MediaBrowser.ServerApplication return repo; } + /// + /// Gets the file organization repository. + /// + /// Task{IUserRepository}. + private async Task GetFileOrganizationRepository() + { + var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths); + + await repo.Initialize().ConfigureAwait(false); + + return repo; + } + /// /// Configures the repositories. /// diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index a02da385da..83043dd43f 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 2066c6cb93..d3b0285d0d 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -169,6 +169,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -418,6 +421,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest