diff options
Diffstat (limited to 'MediaBrowser.Server.Implementations/Persistence')
| -rw-r--r-- | MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs | 77 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs | 160 |
2 files changed, 225 insertions, 12 deletions
diff --git a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs index 9f87483ba..c9f7165cb 100644 --- a/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Persistence/CleanDatabaseScheduledTask.cs @@ -1,15 +1,18 @@ -using MediaBrowser.Common.Progress; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Progress; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Entities.Audio; namespace MediaBrowser.Server.Implementations.Persistence { @@ -19,13 +22,15 @@ namespace MediaBrowser.Server.Implementations.Persistence private readonly IItemRepository _itemRepo; private readonly ILogger _logger; private readonly IServerConfigurationManager _config; + private readonly IFileSystem _fileSystem; - public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config) + public CleanDatabaseScheduledTask(ILibraryManager libraryManager, IItemRepository itemRepo, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem) { _libraryManager = libraryManager; _itemRepo = itemRepo; _logger = logger; _config = config; + _fileSystem = fileSystem; } public string Name @@ -46,15 +51,18 @@ namespace MediaBrowser.Server.Implementations.Persistence public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { var innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report(.95 * p)); + innerProgress.RegisterAction(p => progress.Report(.4 * p)); await UpdateToLatestSchema(cancellationToken, innerProgress).ConfigureAwait(false); innerProgress = new ActionableProgress<double>(); - innerProgress.RegisterAction(p => progress.Report(95 + (.05 * p))); - - //await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false); + innerProgress.RegisterAction(p => progress.Report(40 + (.05 * p))); + await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false); + progress.Report(45); + innerProgress = new ActionableProgress<double>(); + innerProgress.RegisterAction(p => progress.Report(45 + (.55 * p))); + await CleanDeletedItems(cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(100); } @@ -77,6 +85,12 @@ namespace MediaBrowser.Server.Implementations.Persistence { cancellationToken.ThrowIfCancellationRequested(); + if (itemId == Guid.Empty) + { + // Somehow some invalid data got into the db. It probably predates the boundary checking + continue; + } + var item = _libraryManager.GetItemById(itemId); if (item != null) @@ -147,11 +161,60 @@ namespace MediaBrowser.Server.Implementations.Persistence progress.Report(100); } + private async Task CleanDeletedItems(CancellationToken cancellationToken, IProgress<double> progress) + { + var result = _itemRepo.GetItemIdsWithPath(new InternalItemsQuery + { + IsOffline = false, + LocationType = LocationType.FileSystem, + //Limit = limit, + + // These have their own cleanup routines + ExcludeItemTypes = new[] { typeof(Person).Name, typeof(Genre).Name, typeof(MusicGenre).Name, typeof(GameGenre).Name, typeof(Studio).Name, typeof(Year).Name } + }); + + var numComplete = 0; + var numItems = result.Items.Length; + + foreach (var item in result.Items) + { + cancellationToken.ThrowIfCancellationRequested(); + + var path = item.Item2; + + try + { + if (!_fileSystem.FileExists(path) && !_fileSystem.DirectoryExists(path)) + { + var libraryItem = _libraryManager.GetItemById(item.Item1); + + await _libraryManager.DeleteItem(libraryItem, new DeleteOptions + { + DeleteFileLocation = false + }); + } + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception ex) + { + _logger.ErrorException("Error in CleanDeletedItems. File {0}", ex, path); + } + + numComplete++; + double percent = numComplete; + percent /= numItems; + progress.Report(percent * 100); + } + } + public IEnumerable<ITaskTrigger> GetDefaultTriggers() { return new ITaskTrigger[] { - new IntervalTrigger{ Interval = TimeSpan.FromDays(1)} + new IntervalTrigger{ Interval = TimeSpan.FromHours(6)} }; } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 00ebf7ea6..3c06973b4 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deletePeopleCommand; private IDbCommand _savePersonCommand; - private const int LatestSchemaVersion = 6; + private const int LatestSchemaVersion = 7; /// <summary> /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class. @@ -175,6 +175,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection.AddColumn(_logger, "TypedBaseItems", "ForcedSortName", "Text"); _connection.AddColumn(_logger, "TypedBaseItems", "IsOffline", "BIT"); + _connection.AddColumn(_logger, "TypedBaseItems", "LocationType", "Text"); PrepareStatements(); @@ -187,11 +188,21 @@ namespace MediaBrowser.Server.Implementations.Persistence /// </summary> private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); - private string[] _retriveItemColumns = + private readonly string[] _retriveItemColumns = { "type", "data", - "IsOffline" + "StartDate", + "EndDate", + "IsOffline", + "ChannelId", + "IsMovie", + "IsSports", + "IsKids", + "CommunityRating", + "CustomRating", + "IndexNumber", + "IsLocked" }; /// <summary> @@ -235,7 +246,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "DateCreated", "DateModified", "ForcedSortName", - "IsOffline" + "IsOffline", + "LocationType" }; _saveItemCommand = _connection.CreateCommand(); _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; @@ -405,6 +417,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.GetParameter(index++).Value = item.ForcedSortName; _saveItemCommand.GetParameter(index++).Value = item.IsOffline; + _saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString(); _saveItemCommand.Transaction = transaction; @@ -511,7 +524,65 @@ namespace MediaBrowser.Server.Implementations.Persistence if (!reader.IsDBNull(2)) { - item.IsOffline = reader.GetBoolean(2); + var hasStartDate = item as IHasStartDate; + if (hasStartDate != null) + { + hasStartDate.StartDate = reader.GetDateTime(2).ToUniversalTime(); + } + } + + if (!reader.IsDBNull(3)) + { + item.EndDate = reader.GetDateTime(3).ToUniversalTime(); + } + + if (!reader.IsDBNull(4)) + { + item.IsOffline = reader.GetBoolean(4); + } + + if (!reader.IsDBNull(5)) + { + item.ChannelId = reader.GetString(5); + } + + var hasProgramAttributes = item as IHasProgramAttributes; + if (hasProgramAttributes != null) + { + if (!reader.IsDBNull(6)) + { + hasProgramAttributes.IsMovie = reader.GetBoolean(6); + } + + if (!reader.IsDBNull(7)) + { + hasProgramAttributes.IsSports = reader.GetBoolean(7); + } + + if (!reader.IsDBNull(8)) + { + hasProgramAttributes.IsKids = reader.GetBoolean(8); + } + } + + if (!reader.IsDBNull(9)) + { + item.CommunityRating = reader.GetFloat(9); + } + + if (!reader.IsDBNull(10)) + { + item.CustomRating = reader.GetString(10); + } + + if (!reader.IsDBNull(11)) + { + item.IndexNumber = reader.GetInt32(11); + } + + if (!reader.IsDBNull(12)) + { + item.IsLocked = reader.GetBoolean(12); } return item; @@ -882,6 +953,75 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + public QueryResult<Tuple<Guid, string>> GetItemIdsWithPath(InternalItemsQuery query) + { + if (query == null) + { + throw new ArgumentNullException("query"); + } + + CheckDisposed(); + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select guid,path from TypedBaseItems"; + + var whereClauses = GetWhereClauses(query, cmd, false); + + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + whereClauses = GetWhereClauses(query, cmd, true); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(CultureInfo.InvariantCulture); + } + + cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + + var list = new List<Tuple<Guid, string>>(); + var count = 0; + + _logger.Debug(cmd.CommandText); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + while (reader.Read()) + { + var id = reader.GetGuid(0); + string path = null; + + if (!reader.IsDBNull(1)) + { + path = reader.GetString(1); + } + list.Add(new Tuple<Guid, string>(id, path)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult<Tuple<Guid, string>>() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } + } + public QueryResult<Guid> GetItemIds(InternalItemsQuery query) { if (query == null) @@ -960,6 +1100,16 @@ namespace MediaBrowser.Server.Implementations.Persistence } cmd.Parameters.Add(cmd, "@SchemaVersion", DbType.Int32).Value = LatestSchemaVersion; } + if (query.IsOffline.HasValue) + { + whereClauses.Add("IsOffline=@IsOffline"); + cmd.Parameters.Add(cmd, "@IsOffline", DbType.Boolean).Value = query.IsOffline; + } + if (query.LocationType.HasValue) + { + whereClauses.Add("LocationType=@LocationType"); + cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationType.Value; + } if (query.IsMovie.HasValue) { whereClauses.Add("IsMovie=@IsMovie"); |
