Browse Source

removed local trailers and special features from memory

Luke Pulverenti 12 năm trước cách đây
mục cha
commit
fbd052abfc
22 tập tin đã thay đổi với 325 bổ sung387 xóa
  1. 1 1
      MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
  2. 6 8
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  3. 9 5
      MediaBrowser.Api/UserLibrary/UserLibraryService.cs
  4. 0 4
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  5. 1 1
      MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
  6. 2 2
      MediaBrowser.Controller/Dto/DtoBuilder.cs
  7. 65 97
      MediaBrowser.Controller/Entities/BaseItem.cs
  8. 26 44
      MediaBrowser.Controller/Entities/Movies/Movie.cs
  9. 8 1
      MediaBrowser.Controller/Persistence/IItemRepository.cs
  10. 5 11
      MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs
  11. 0 1
      MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs
  12. 0 1
      MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs
  13. 0 1
      MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs
  14. 6 49
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  15. 13 15
      MediaBrowser.Server.Implementations/ScheduledTasks/ImageCleanupTask.cs
  16. 11 4
      MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
  17. 22 20
      MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
  18. 62 41
      MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
  19. 10 6
      MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
  20. 37 33
      MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
  21. 38 32
      MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
  22. 3 10
      MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs

+ 1 - 1
MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs

@@ -96,7 +96,7 @@ namespace MediaBrowser.Api.Playback.Progressive
 
                     var bytesRead = fsPosition - position;
 
-                    Logger.Debug("Streamed {0} bytes from file {1}", bytesRead, path);
+                    //Logger.Debug("Streamed {0} bytes from file {1}", bytesRead, path);
 
                     if (bytesRead == 0)
                     {

+ 6 - 8
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -547,22 +547,22 @@ namespace MediaBrowser.Api.UserLibrary
 
             if (request.HasTrailer.HasValue)
             {
-                items = items.Where(i => request.HasTrailer.Value ? i.LocalTrailers.Count > 0 : i.LocalTrailers.Count == 0);
+                items = items.Where(i => request.HasTrailer.Value ? i.LocalTrailerIds.Count > 0 : i.LocalTrailerIds.Count == 0);
             }
 
             if (request.HasThemeSong.HasValue)
             {
-                items = items.Where(i => request.HasThemeSong.Value ? i.ThemeSongs.Count > 0 : i.ThemeSongs.Count == 0);
+                items = items.Where(i => request.HasThemeSong.Value ? i.ThemeSongIds.Count > 0 : i.ThemeSongIds.Count == 0);
             }
 
             if (request.HasThemeVideo.HasValue)
             {
-                items = items.Where(i => request.HasThemeVideo.Value ? i.ThemeVideos.Count > 0 : i.ThemeVideos.Count == 0);
+                items = items.Where(i => request.HasThemeVideo.Value ? i.ThemeVideoIds.Count > 0 : i.ThemeVideoIds.Count == 0);
             }
 
             if (request.HasSpecialFeature.HasValue)
             {
-                items = items.OfType<Movie>().Where(i => request.HasSpecialFeature.Value ? i.SpecialFeatures.Count > 0 : i.SpecialFeatures.Count == 0);
+                items = items.OfType<Movie>().Where(i => request.HasSpecialFeature.Value ? i.SpecialFeatureIds.Count > 0 : i.SpecialFeatureIds.Count == 0);
             }
 
             if (request.HasSubtitles.HasValue)
@@ -573,10 +573,8 @@ namespace MediaBrowser.Api.UserLibrary
                     {
                         return i.MediaStreams != null && i.MediaStreams.Any(m => m.Type == MediaStreamType.Subtitle);
                     }
-                    else
-                    {
-                        return i.MediaStreams == null || i.MediaStreams.All(m => m.Type != MediaStreamType.Subtitle);
-                    }
+
+                    return i.MediaStreams == null || i.MediaStreams.All(m => m.Type != MediaStreamType.Subtitle);
                 });
             }
 

+ 9 - 5
MediaBrowser.Api/UserLibrary/UserLibraryService.cs

@@ -399,19 +399,23 @@ namespace MediaBrowser.Api.UserLibrary
         /// </summary>
         private readonly ILibraryManager _libraryManager;
 
+        private readonly IItemRepository _itemRepo;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="UserLibraryService" /> class.
         /// </summary>
         /// <param name="userManager">The user manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
+        /// <param name="itemRepo">The item repo.</param>
         /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
-        public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
+        public UserLibraryService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository, IItemRepository itemRepo)
             : base()
         {
             _userManager = userManager;
             _libraryManager = libraryManager;
             _userDataRepository = userDataRepository;
+            _itemRepo = itemRepo;
         }
 
         /// <summary>
@@ -432,7 +436,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = movie.SpecialFeatures.OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToList();
+            var items = _itemRepo.GetItems(movie.SpecialFeatureIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToList();
 
             return ToOptimizedResult(items);
         }
@@ -453,7 +457,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = item.LocalTrailers.OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToList();
+            var items = _itemRepo.GetItems(item.LocalTrailerIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToList();
 
             return ToOptimizedResult(items);
         }
@@ -474,7 +478,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = item.ThemeSongs.OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToArray();
+            var items = _itemRepo.GetItems(item.ThemeSongIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToArray();
 
             var result = new ThemeSongsResult
             {
@@ -502,7 +506,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = item.ThemeVideos.OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToArray();
+            var items = _itemRepo.GetItems(item.ThemeVideoIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, user, fields)).Select(t => t.Result).ToArray();
 
             var result = new ThemeVideosResult
             {

+ 0 - 4
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -340,8 +340,6 @@ namespace MediaBrowser.Common.Implementations
         protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
             where T : class
         {
-            Logger.Info("Registering " + obj.GetType().Name);
-
             Container.RegisterSingle(obj);
 
             if (manageLifetime)
@@ -421,8 +419,6 @@ namespace MediaBrowser.Common.Implementations
         {
             var currentType = typeof(T);
 
-            Logger.Info("Composing instances of " + currentType.Name);
-
             var parts = AllConcreteTypes.AsParallel().Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray();
 
             if (manageLiftime)

+ 1 - 1
MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs

@@ -136,7 +136,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
                 {
                     var now = DateTime.UtcNow;
 
-                    var isCacheValid = (!cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 14)
+                    var isCacheValid = (!cachedInfo.MustRevalidate && !string.IsNullOrEmpty(cachedInfo.Etag) && (now - cachedInfo.RequestDate).TotalDays < 7)
                         || (cachedInfo.Expires.HasValue && cachedInfo.Expires.Value > now);
 
                     if (isCacheValid)

+ 2 - 2
MediaBrowser.Controller/Dto/DtoBuilder.cs

@@ -331,7 +331,7 @@ namespace MediaBrowser.Controller.Dto
                 dto.CriticRatingSummary = item.CriticRatingSummary;
             }
 
-            var localTrailerCount = item.LocalTrailers == null ? 0 : item.LocalTrailers.Count;
+            var localTrailerCount = item.LocalTrailerIds.Count;
 
             if (localTrailerCount > 0)
             {
@@ -492,7 +492,7 @@ namespace MediaBrowser.Controller.Dto
 
             if (movie != null)
             {
-                var specialFeatureCount = movie.SpecialFeatures == null ? 0 : movie.SpecialFeatures.Count;
+                var specialFeatureCount = movie.SpecialFeatureIds.Count;
 
                 if (specialFeatureCount > 0)
                 {

+ 65 - 97
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -38,6 +38,9 @@ namespace MediaBrowser.Controller.Entities
             Images = new Dictionary<ImageType, string>();
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             Tags = new List<string>();
+            ThemeSongIds = new List<Guid>();
+            ThemeVideoIds = new List<Guid>();
+            LocalTrailerIds = new List<Guid>();
         }
 
         /// <summary>
@@ -572,7 +575,7 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value>The tags.</value>
         public List<string> Tags { get; set; }
-        
+
         /// <summary>
         /// Override this if you need to combine/collapse person information
         /// </summary>
@@ -612,7 +615,7 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value>The revenue.</value>
         public double? Revenue { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the production locations.
         /// </summary>
@@ -630,7 +633,7 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value>The critic rating summary.</value>
         public string CriticRatingSummary { get; set; }
-        
+
         /// <summary>
         /// Gets or sets the community rating.
         /// </summary>
@@ -672,84 +675,9 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The critic reviews.</value>
         public List<ItemReview> CriticReviews { get; set; }
 
-        /// <summary>
-        /// The _local trailers
-        /// </summary>
-        private List<Trailer> _localTrailers;
-        /// <summary>
-        /// The _local trailers initialized
-        /// </summary>
-        private bool _localTrailersInitialized;
-        /// <summary>
-        /// The _local trailers sync lock
-        /// </summary>
-        private object _localTrailersSyncLock = new object();
-        /// <summary>
-        /// Gets the local trailers.
-        /// </summary>
-        /// <value>The local trailers.</value>
-        [IgnoreDataMember]
-        public List<Trailer> LocalTrailers
-        {
-            get
-            {
-                LazyInitializer.EnsureInitialized(ref _localTrailers, ref _localTrailersInitialized, ref _localTrailersSyncLock, LoadLocalTrailers);
-                return _localTrailers;
-            }
-            private set
-            {
-                _localTrailers = value;
-
-                if (value == null)
-                {
-                    _localTrailersInitialized = false;
-                }
-            }
-        }
-
-        private List<Audio.Audio> _themeSongs;
-        private bool _themeSongsInitialized;
-        private object _themeSongsSyncLock = new object();
-        [IgnoreDataMember]
-        public List<Audio.Audio> ThemeSongs
-        {
-            get
-            {
-                LazyInitializer.EnsureInitialized(ref _themeSongs, ref _themeSongsInitialized, ref _themeSongsSyncLock, LoadThemeSongs);
-                return _themeSongs;
-            }
-            private set
-            {
-                _themeSongs = value;
-
-                if (value == null)
-                {
-                    _themeSongsInitialized = false;
-                }
-            }
-        }
-
-        private List<Video> _themeVideos;
-        private bool _themeVideosInitialized;
-        private object _themeVideosSyncLock = new object();
-        [IgnoreDataMember]
-        public List<Video> ThemeVideos
-        {
-            get
-            {
-                LazyInitializer.EnsureInitialized(ref _themeVideos, ref _themeVideosInitialized, ref _themeVideosSyncLock, LoadThemeVideos);
-                return _themeVideos;
-            }
-            private set
-            {
-                _themeVideos = value;
-
-                if (value == null)
-                {
-                    _themeVideosInitialized = false;
-                }
-            }
-        }
+        public List<Guid> ThemeSongIds { get; set; }
+        public List<Guid> ThemeVideoIds { get; set; }
+        public List<Guid> LocalTrailerIds { get; set; }
 
         /// <summary>
         /// Loads local trailers from the file system
@@ -956,36 +884,25 @@ namespace MediaBrowser.Controller.Entities
                 ResolveArgs = null;
             }
 
-            // Lazy load these again
-            LocalTrailers = null;
-            ThemeSongs = null;
-            ThemeVideos = null;
-
             // Refresh for the item
             var itemRefreshTask = ProviderManager.ExecuteMetadataProviders(this, cancellationToken, forceRefresh, allowSlowProviders);
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            // Refresh metadata for local trailers
-            var trailerTasks = LocalTrailers.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
+            var themeSongsChanged = await RefreshThemeSongs(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
 
-            var themeSongTasks = ThemeSongs.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
+            var themeVideosChanged = await RefreshThemeVideos(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
 
-            var videoBackdropTasks = ThemeVideos.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
-            
-            cancellationToken.ThrowIfCancellationRequested();
+            var localTrailersChanged = await RefreshLocalTrailers(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
 
-            // Await the trailer tasks
-            await Task.WhenAll(trailerTasks).ConfigureAwait(false);
-            await Task.WhenAll(themeSongTasks).ConfigureAwait(false);
-            await Task.WhenAll(videoBackdropTasks).ConfigureAwait(false);
+            cancellationToken.ThrowIfCancellationRequested();
 
             cancellationToken.ThrowIfCancellationRequested();
 
             // Get the result from the item task
             var changed = await itemRefreshTask.ConfigureAwait(false);
 
-            if (changed || forceSave)
+            if (changed || forceSave || themeSongsChanged || themeVideosChanged || localTrailersChanged)
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
@@ -995,6 +912,57 @@ namespace MediaBrowser.Controller.Entities
             return changed;
         }
 
+        private async Task<bool> RefreshLocalTrailers(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
+        {
+            var newItems = LoadLocalTrailers().ToList();
+            var newItemIds = newItems.Select(i => i.Id).ToList();
+
+            var itemsChanged = !LocalTrailerIds.SequenceEqual(newItemIds);
+
+            var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
+
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+
+            LocalTrailerIds = newItemIds;
+
+            return itemsChanged || results.Contains(true);
+        }
+        
+        private async Task<bool> RefreshThemeVideos(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
+        {
+            var newThemeVideos = LoadThemeVideos().ToList();
+            var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToList();
+
+            var themeVideosChanged = !ThemeVideoIds.SequenceEqual(newThemeVideoIds);
+
+            var tasks = newThemeVideos.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
+
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+
+            ThemeVideoIds = newThemeVideoIds;
+
+            return themeVideosChanged || results.Contains(true);
+        }
+        
+        /// <summary>
+        /// Refreshes the theme songs.
+        /// </summary>
+        private async Task<bool> RefreshThemeSongs(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
+        {
+            var newThemeSongs = LoadThemeSongs().ToList();
+            var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToList();
+
+            var themeSongsChanged = !ThemeSongIds.SequenceEqual(newThemeSongIds);
+
+            var tasks = newThemeSongs.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
+
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+
+            ThemeSongIds = newThemeSongIds;
+
+            return themeSongsChanged || results.Contains(true);
+        }
+
         /// <summary>
         /// Clear out all metadata properties. Extend for sub-classes.
         /// </summary>

+ 26 - 44
MediaBrowser.Controller/Entities/Movies/Movie.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.IO;
+using System;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Entities;
 using System.Collections.Generic;
 using System.IO;
@@ -14,6 +15,13 @@ namespace MediaBrowser.Controller.Entities.Movies
     /// </summary>
     public class Movie : Video
     {
+        public List<Guid> SpecialFeatureIds { get; set; }
+
+        public Movie()
+        {
+            SpecialFeatureIds = new List<Guid>();
+        }
+        
         /// <summary>
         /// Should be overridden to return the proper folder where metadata lives
         /// </summary>
@@ -36,41 +44,6 @@ namespace MediaBrowser.Controller.Entities.Movies
             return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey();
         }
 
-        /// <summary>
-        /// The _special features
-        /// </summary>
-        private List<Video> _specialFeatures;
-        /// <summary>
-        /// The _special features initialized
-        /// </summary>
-        private bool _specialFeaturesInitialized;
-        /// <summary>
-        /// The _special features sync lock
-        /// </summary>
-        private object _specialFeaturesSyncLock = new object();
-        /// <summary>
-        /// Gets the special features.
-        /// </summary>
-        /// <value>The special features.</value>
-        [IgnoreDataMember]
-        public List<Video> SpecialFeatures
-        {
-            get
-            {
-                LazyInitializer.EnsureInitialized(ref _specialFeatures, ref _specialFeaturesInitialized, ref _specialFeaturesSyncLock, () => LoadSpecialFeatures().ToList());
-                return _specialFeatures;
-            }
-            private set
-            {
-                _specialFeatures = value;
-
-                if (value == null)
-                {
-                    _specialFeaturesInitialized = false;
-                }
-            }
-        }
-
         /// <summary>
         /// Needed because the resolver stops at the movie folder and we find the video inside.
         /// </summary>
@@ -94,21 +67,30 @@ namespace MediaBrowser.Controller.Entities.Movies
         /// <returns>Task{System.Boolean}.</returns>
         public override async Task<bool> RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)
         {
-            // Lazy load these again
-            SpecialFeatures = null;
-
             // Kick off a task to refresh the main item
             var result = await base.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs).ConfigureAwait(false);
 
-            var tasks = SpecialFeatures.Select(item => item.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
+            var specialFeaturesChanged = await RefreshSpecialFeatures(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
 
-            await Task.WhenAll(tasks).ConfigureAwait(false);
+            return specialFeaturesChanged || result;
+        }
+
+        private async Task<bool> RefreshSpecialFeatures(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
+        {
+            var newItems = LoadSpecialFeatures().ToList();
+            var newItemIds = newItems.Select(i => i.Id).ToList();
 
-            cancellationToken.ThrowIfCancellationRequested();
+            var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
 
-            return result;
-        }
+            var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
 
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+
+            SpecialFeatureIds = newItemIds;
+
+            return itemsChanged || results.Contains(true);
+        }
+        
         /// <summary>
         /// Loads the special features.
         /// </summary>

+ 8 - 1
MediaBrowser.Controller/Persistence/IItemRepository.cs

@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Persistence
         /// </summary>
         /// <param name="id">The id.</param>
         /// <returns>BaseItem.</returns>
-        BaseItem RetrieveItem(Guid id);
+        BaseItem GetItem(Guid id);
 
         /// <summary>
         /// Gets children of a given Folder
@@ -33,6 +33,13 @@ namespace MediaBrowser.Controller.Persistence
         /// <returns>IEnumerable{BaseItem}.</returns>
         IEnumerable<BaseItem> RetrieveChildren(Folder parent);
 
+        /// <summary>
+        /// Retrieves the items.
+        /// </summary>
+        /// <param name="ids">The ids.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        IEnumerable<BaseItem> GetItems(IEnumerable<Guid> ids);
+
         /// <summary>
         /// Saves children of a given Folder
         /// </summary>

+ 5 - 11
MediaBrowser.Controller/Providers/Music/LastfmArtistProvider.cs

@@ -57,15 +57,9 @@ namespace MediaBrowser.Controller.Providers.Music
 
             if (result != null)
             {
-                if (!string.IsNullOrEmpty(result.Item1))
+                if (!string.IsNullOrEmpty(result))
                 {
-                    return result.Item1;
-                }
-
-                // If there were no artists returned at all, then don't bother with musicbrainz
-                if (!result.Item2)
-                {
-                    return null;
+                    return result;
                 }
             }
 
@@ -94,7 +88,7 @@ namespace MediaBrowser.Controller.Providers.Music
             return artist != null ? artist.GetProviderId(MetadataProviders.Musicbrainz) : null;
         }
 
-        private async Task<Tuple<string,bool>> FindIdFromLastFm(BaseItem item, CancellationToken cancellationToken)
+        private async Task<string> FindIdFromLastFm(BaseItem item, CancellationToken cancellationToken)
         {
             //Execute the Artist search against our name and assume first one is the one we want
             var url = RootUrl + string.Format("method=artist.search&artist={0}&api_key={1}&format=json", UrlEncode(item.Name), ApiKey);
@@ -125,10 +119,10 @@ namespace MediaBrowser.Controller.Providers.Music
                 var artist = searchResult.results.artistmatches.artist.FirstOrDefault(i => i.name != null && string.Compare(i.name, item.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace) == 0) ??
                     searchResult.results.artistmatches.artist.First();
 
-                return new Tuple<string, bool>(artist.mbid, true);
+                return artist.mbid;
             }
 
-            return new Tuple<string,bool>(null, false);
+            return null;
         }
 
         private async Task<string> FindIdFromMusicBrainz(BaseItem item, CancellationToken cancellationToken)

+ 0 - 1
MediaBrowser.Controller/Providers/TV/RemoteEpisodeProvider.cs

@@ -146,7 +146,6 @@ namespace MediaBrowser.Controller.Providers.TV
             string name = episode.Name;
             string location = episode.Path;
 
-            Logger.Debug("TvDbProvider: Fetching episode data for: " + name);
             string epNum = TVUtils.EpisodeNumberFromFile(location, episode.Season != null);
 
             if (epNum == null)

+ 0 - 1
MediaBrowser.Controller/Providers/TV/RemoteSeasonProvider.cs

@@ -130,7 +130,6 @@ namespace MediaBrowser.Controller.Providers.TV
         {
             string name = season.Name;
 
-            Logger.Debug("TvDbProvider: Fetching season data: " + name);
             var seasonNumber = TVUtils.GetSeasonNumberFromPath(season.Path) ?? -1;
 
             season.IndexNumber = seasonNumber;

+ 0 - 1
MediaBrowser.Controller/Providers/TV/RemoteSeriesProvider.cs

@@ -193,7 +193,6 @@ namespace MediaBrowser.Controller.Providers.TV
             var success = false;
 
             var name = series.Name;
-            Logger.Debug("TvDbProvider: Fetching series data: " + name);
 
             if (!string.IsNullOrEmpty(seriesId))
             {

+ 6 - 49
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -4,7 +4,6 @@ using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -267,16 +266,6 @@ namespace MediaBrowser.Server.Implementations.Library
 
             items.Add(RootFolder);
 
-            var specialFeatures = items.OfType<Movie>().SelectMany(i => i.SpecialFeatures).ToList();
-            var localTrailers = items.SelectMany(i => i.LocalTrailers).ToList();
-            var themeSongs = items.SelectMany(i => i.ThemeSongs).ToList();
-            var themeVideos = items.SelectMany(i => i.ThemeVideos).ToList();
-
-            items.AddRange(specialFeatures);
-            items.AddRange(localTrailers);
-            items.AddRange(themeSongs);
-            items.AddRange(themeVideos);
-
             // Need to use DistinctBy Id because there could be multiple instances with the same id
             // due to sharing the default library
             var userRootFolders = _userManager.Users.Select(i => i.RootFolder)
@@ -304,39 +293,6 @@ namespace MediaBrowser.Server.Implementations.Library
         private void UpdateItemInLibraryCache(BaseItem item)
         {
             LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
-
-            foreach (var subItem in item.LocalTrailers)
-            {
-                // Prevent access to foreach variable in closure
-                var copy = subItem;
-                LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return copy; });
-            }
-
-            foreach (var subItem in item.ThemeSongs)
-            {
-                // Prevent access to foreach variable in closure
-                var copy = subItem;
-                LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return copy; });
-            }
-
-            foreach (var subItem in item.ThemeVideos)
-            {
-                // Prevent access to foreach variable in closure
-                var copy = subItem;
-                LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return copy; });
-            }
-
-            var movie = item as Movie;
-
-            if (movie != null)
-            {
-                foreach (var subItem in movie.SpecialFeatures)
-                {
-                    // Prevent access to foreach variable in closure
-                    var special1 = subItem;
-                    LibraryItemsCache.AddOrUpdate(subItem.Id, subItem, delegate { return special1; });
-                }
-            }
         }
 
         /// <summary>
@@ -661,8 +617,6 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            _logger.Debug("Getting {0}: {1}", typeof(T).Name, name);
-
             path = Path.Combine(path, FileSystem.GetValidFilename(name));
 
             var fileInfo = new DirectoryInfo(path);
@@ -968,9 +922,12 @@ namespace MediaBrowser.Server.Implementations.Library
 
             BaseItem item;
 
-            LibraryItemsCache.TryGetValue(id, out item);
+            if (LibraryItemsCache.TryGetValue(id, out item))
+            {
+                return item;
+            }
 
-            return item;
+            return ItemRepository.GetItem(id);
         }
 
         /// <summary>
@@ -1130,7 +1087,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task{BaseItem}.</returns>
         public BaseItem RetrieveItem(Guid id)
         {
-            return ItemRepository.RetrieveItem(id);
+            return ItemRepository.GetItem(id);
         }
 
         /// <summary>

+ 13 - 15
MediaBrowser.Server.Implementations/ScheduledTasks/ImageCleanupTask.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
@@ -28,6 +29,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         private readonly ILogger _logger;
         private readonly ILibraryManager _libraryManager;
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IItemRepository _itemRepo;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageCleanupTask" /> class.
@@ -36,12 +38,13 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         /// <param name="logger">The logger.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="appPaths">The app paths.</param>
-        public ImageCleanupTask(Kernel kernel, ILogger logger, ILibraryManager libraryManager, IServerApplicationPaths appPaths)
+        public ImageCleanupTask(Kernel kernel, ILogger logger, ILibraryManager libraryManager, IServerApplicationPaths appPaths, IItemRepository itemRepo)
         {
             _kernel = kernel;
             _logger = logger;
             _libraryManager = libraryManager;
             _appPaths = appPaths;
+            _itemRepo = itemRepo;
         }
 
         /// <summary>
@@ -138,20 +141,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
                 images = images.Concat(item.ScreenshotImagePaths);
             }
 
-            if (item.LocalTrailers != null)
-            {
-                images = item.LocalTrailers.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
-            }
+            var localTrailers = _itemRepo.GetItems(item.LocalTrailerIds).ToList();
+            images = localTrailers.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
 
-            if (item.ThemeSongs != null)
-            {
-                images = item.ThemeSongs.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
-            }
+            var themeSongs = _itemRepo.GetItems(item.ThemeSongIds).ToList();
+            images = themeSongs.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
 
-            if (item.ThemeVideos != null)
-            {
-                images = item.ThemeVideos.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
-            }
+            var themeVideos = _itemRepo.GetItems(item.ThemeVideoIds).ToList();
+            images = themeVideos.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
 
             var video = item as Video;
 
@@ -162,9 +159,10 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
 
             var movie = item as Movie;
 
-            if (movie != null && movie.SpecialFeatures != null)
+            if (movie != null)
             {
-                images = movie.SpecialFeatures.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
+                var specialFeattures = _itemRepo.GetItems(movie.SpecialFeatureIds).ToList();
+                images = specialFeattures.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));
             }
             
             return images;

+ 11 - 4
MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers.MediaInfo;
 using MediaBrowser.Model.Entities;
 using System;
@@ -43,6 +44,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         /// </summary>
         private readonly IIsoManager _isoManager;
 
+        private readonly IItemRepository _itemRepo;
+        
         private readonly ILogger _logger;
         
         /// <summary>
@@ -67,11 +70,12 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         /// <param name="logManager">The log manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
         /// <param name="isoManager">The iso manager.</param>
-        public VideoImagesTask(ILibraryManager libraryManager, ILogManager logManager, IMediaEncoder mediaEncoder, IIsoManager isoManager)
+        public VideoImagesTask(ILibraryManager libraryManager, ILogManager logManager, IMediaEncoder mediaEncoder, IIsoManager isoManager, IItemRepository itemRepo)
         {
             _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
             _isoManager = isoManager;
+            _itemRepo = itemRepo;
             _logger = logManager.GetLogger(GetType().Name);
 
             ImageCache = new FileSystemRepository(Kernel.Instance.FFMpegManager.VideoImagesDataPath);
@@ -205,15 +209,18 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         {
             var allItems = sourceItems.ToList();
 
-            var localTrailers = allItems.SelectMany(i => i.LocalTrailers);
-            var themeVideos = allItems.SelectMany(i => i.ThemeVideos);
+            var localTrailers = allItems.SelectMany(i => _itemRepo.GetItems(i.LocalTrailerIds).Cast<Video>());
+
+            var themeVideos = allItems.SelectMany(i => _itemRepo.GetItems(i.ThemeVideoIds).Cast<Video>());
 
             var videos = allItems.OfType<Video>().ToList();
 
             var items = videos;
             items.AddRange(localTrailers);
+
             items.AddRange(themeVideos);
-            items.AddRange(videos.OfType<Movie>().SelectMany(i => i.SpecialFeatures).ToList());
+
+            items.AddRange(videos.OfType<Movie>().SelectMany(i => _itemRepo.GetItems(i.SpecialFeatureIds).Cast<Video>()).ToList());
 
             return items.Where(i =>
             {

+ 22 - 20
MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs

@@ -132,29 +132,31 @@ namespace MediaBrowser.Server.Implementations.Sqlite
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "replace into displaypreferences (id, data) values (@1, @2)";
-            cmd.AddParam("@1", displayPreferences.Id);
-            cmd.AddParam("@2", serialized);
-
-            using (var tran = connection.BeginTransaction())
+            using (var cmd = connection.CreateCommand())
             {
-                try
+                cmd.CommandText = "replace into displaypreferences (id, data) values (@1, @2)";
+                cmd.AddParam("@1", displayPreferences.Id);
+                cmd.AddParam("@2", serialized);
+
+                using (var tran = connection.BeginTransaction())
                 {
-                    cmd.Transaction = tran;
+                    try
+                    {
+                        cmd.Transaction = tran;
 
-                    await cmd.ExecuteNonQueryAsync(cancellationToken);
+                        await cmd.ExecuteNonQueryAsync(cancellationToken);
 
-                    tran.Commit();
-                }
-                catch (OperationCanceledException)
-                {
-                    tran.Rollback();
-                }
-                catch (Exception e)
-                {
-                    Logger.ErrorException("Failed to commit transaction.", e);
-                    tran.Rollback();
+                        tran.Commit();
+                    }
+                    catch (OperationCanceledException)
+                    {
+                        tran.Rollback();
+                    }
+                    catch (Exception e)
+                    {
+                        Logger.ErrorException("Failed to commit transaction.", e);
+                        tran.Rollback();
+                    }
                 }
             }
         }
@@ -174,7 +176,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
 
             var cmd = connection.CreateCommand();
             cmd.CommandText = "select data from displaypreferences where id = @id";
-            
+
             var idParam = cmd.Parameters.Add("@id", DbType.Guid);
             idParam.Value = displayPreferencesId;
 

+ 62 - 41
MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs

@@ -1,3 +1,4 @@
+using System.Linq;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
@@ -156,16 +157,32 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         /// <param name="id">The id.</param>
         /// <returns>BaseItem.</returns>
         /// <exception cref="System.ArgumentException"></exception>
-        public BaseItem RetrieveItem(Guid id)
+        public BaseItem GetItem(Guid id)
         {
             if (id == Guid.Empty)
             {
-                throw new ArgumentException();
+                throw new ArgumentNullException("id");
             }
 
             return RetrieveItemInternal(id);
         }
 
+        /// <summary>
+        /// Retrieves the items.
+        /// </summary>
+        /// <param name="ids">The ids.</param>
+        /// <returns>IEnumerable{BaseItem}.</returns>
+        /// <exception cref="System.ArgumentNullException">ids</exception>
+        public IEnumerable<BaseItem> GetItems(IEnumerable<Guid> ids)
+        {
+            if (ids == null)
+            {
+                throw new ArgumentNullException("ids");
+            }
+
+            return ids.Select(RetrieveItemInternal);
+        }
+
         /// <summary>
         /// Internal retrieve from items or users table
         /// </summary>
@@ -176,35 +193,37 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         {
             if (id == Guid.Empty)
             {
-                throw new ArgumentException();
+                throw new ArgumentNullException("id");
             }
 
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "select obj_type,data from items where guid = @guid";
-            var guidParam = cmd.Parameters.Add("@guid", DbType.Guid);
-            guidParam.Value = id;
-
-            using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+            using (var cmd = connection.CreateCommand())
             {
-                if (reader.Read())
+                cmd.CommandText = "select obj_type,data from items where guid = @guid";
+                var guidParam = cmd.Parameters.Add("@guid", DbType.Guid);
+                guidParam.Value = id;
+
+                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
                 {
-                    var type = reader.GetString(0);
-                    using (var stream = GetStream(reader, 1))
+                    if (reader.Read())
                     {
-                        var itemType = _typeMapper.GetType(type);
-
-                        if (itemType == null)
+                        var type = reader.GetString(0);
+                        using (var stream = GetStream(reader, 1))
                         {
-                            Logger.Error("Cannot find type {0}.  Probably belongs to plug-in that is no longer loaded.", type);
-                            return null;
-                        }
+                            var itemType = _typeMapper.GetType(type);
 
-                        var item = _jsonSerializer.DeserializeFromStream(stream, itemType);
-                        return item as BaseItem;
+                            if (itemType == null)
+                            {
+                                Logger.Error("Cannot find type {0}.  Probably belongs to plug-in that is no longer loaded.", type);
+                                return null;
+                            }
+
+                            var item = _jsonSerializer.DeserializeFromStream(stream, itemType);
+                            return item as BaseItem;
+                        }
                     }
                 }
+                return null;
             }
-            return null;
         }
 
         /// <summary>
@@ -220,30 +239,32 @@ namespace MediaBrowser.Server.Implementations.Sqlite
                 throw new ArgumentNullException();
             }
 
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "select obj_type,data from items where guid in (select child from children where guid = @guid)";
-            var guidParam = cmd.Parameters.Add("@guid", DbType.Guid);
-            guidParam.Value = parent.Id;
-
-            using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+            using (var cmd = connection.CreateCommand())
             {
-                while (reader.Read())
-                {
-                    var type = reader.GetString(0);
+                cmd.CommandText = "select obj_type,data from items where guid in (select child from children where guid = @guid)";
+                var guidParam = cmd.Parameters.Add("@guid", DbType.Guid);
+                guidParam.Value = parent.Id;
 
-                    using (var stream = GetStream(reader, 1))
+                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+                {
+                    while (reader.Read())
                     {
-                        var itemType = _typeMapper.GetType(type);
-                        if (itemType == null)
-                        {
-                            Logger.Error("Cannot find type {0}.  Probably belongs to plug-in that is no longer loaded.", type);
-                            continue;
-                        }
-                        var item = _jsonSerializer.DeserializeFromStream(stream, itemType) as BaseItem;
-                        if (item != null)
+                        var type = reader.GetString(0);
+
+                        using (var stream = GetStream(reader, 1))
                         {
-                            item.Parent = parent;
-                            yield return item;
+                            var itemType = _typeMapper.GetType(type);
+                            if (itemType == null)
+                            {
+                                Logger.Error("Cannot find type {0}.  Probably belongs to plug-in that is no longer loaded.", type);
+                                continue;
+                            }
+                            var item = _jsonSerializer.DeserializeFromStream(stream, itemType) as BaseItem;
+                            if (item != null)
+                            {
+                                item.Parent = parent;
+                                yield return item;
+                            }
                         }
                     }
                 }

+ 10 - 6
MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs

@@ -121,13 +121,14 @@ namespace MediaBrowser.Server.Implementations.Sqlite
             {
                 try
                 {
-                    var cmd = connection.CreateCommand();
-
-                    foreach (var query in queries)
+                    using (var cmd = connection.CreateCommand())
                     {
-                        cmd.Transaction = tran;
-                        cmd.CommandText = query;
-                        cmd.ExecuteNonQuery();
+                        foreach (var query in queries)
+                        {
+                            cmd.Transaction = tran;
+                            cmd.CommandText = query;
+                            cmd.ExecuteNonQuery();
+                        }
                     }
 
                     tran.Commit();
@@ -268,6 +269,9 @@ namespace MediaBrowser.Server.Implementations.Sqlite
                         command.Transaction = tran;
 
                         command.ExecuteNonQuery();
+
+                        command.Dispose();
+
                         numCommands++;
                     }
 

+ 37 - 33
MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs

@@ -184,30 +184,32 @@ namespace MediaBrowser.Server.Implementations.Sqlite
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "replace into userdata (key, userId, data) values (@1, @2, @3)";
-            cmd.AddParam("@1", key);
-            cmd.AddParam("@2", userId);
-            cmd.AddParam("@3", serialized);
-
-            using (var tran = connection.BeginTransaction())
+            using (var cmd = connection.CreateCommand())
             {
-                try
+                cmd.CommandText = "replace into userdata (key, userId, data) values (@1, @2, @3)";
+                cmd.AddParam("@1", key);
+                cmd.AddParam("@2", userId);
+                cmd.AddParam("@3", serialized);
+
+                using (var tran = connection.BeginTransaction())
                 {
-                    cmd.Transaction = tran;
+                    try
+                    {
+                        cmd.Transaction = tran;
 
-                    await cmd.ExecuteNonQueryAsync(cancellationToken);
+                        await cmd.ExecuteNonQueryAsync(cancellationToken);
 
-                    tran.Commit();
-                }
-                catch (OperationCanceledException)
-                {
-                    tran.Rollback();
-                }
-                catch (Exception e)
-                {
-                    Logger.ErrorException("Failed to commit transaction.", e);
-                    tran.Rollback();
+                        tran.Commit();
+                    }
+                    catch (OperationCanceledException)
+                    {
+                        tran.Rollback();
+                    }
+                    catch (Exception e)
+                    {
+                        Logger.ErrorException("Failed to commit transaction.", e);
+                        tran.Rollback();
+                    }
                 }
             }
         }
@@ -245,27 +247,29 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         /// <returns>Task{UserItemData}.</returns>
         private async Task<UserItemData> RetrieveUserData(Guid userId, string key)
         {
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "select data from userdata where key = @key and userId=@userId";
+            using (var cmd = connection.CreateCommand())
+            {
+                cmd.CommandText = "select data from userdata where key = @key and userId=@userId";
 
-            var idParam = cmd.Parameters.Add("@key", DbType.String);
-            idParam.Value = key;
+                var idParam = cmd.Parameters.Add("@key", DbType.String);
+                idParam.Value = key;
 
-            var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid);
-            userIdParam.Value = userId;
+                var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid);
+                userIdParam.Value = userId;
 
-            using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow).ConfigureAwait(false))
-            {
-                if (reader.Read())
+                using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow).ConfigureAwait(false))
                 {
-                    using (var stream = GetStream(reader, 0))
+                    if (reader.Read())
                     {
-                        return _jsonSerializer.DeserializeFromStream<UserItemData>(stream);
+                        using (var stream = GetStream(reader, 0))
+                        {
+                            return _jsonSerializer.DeserializeFromStream<UserItemData>(stream);
+                        }
                     }
                 }
-            }
 
-            return new UserItemData();
+                return new UserItemData();
+            }
         }
     }
 }

+ 38 - 32
MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs

@@ -127,29 +127,31 @@ namespace MediaBrowser.Server.Implementations.Sqlite
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
-            cmd.AddParam("@1", user.Id);
-            cmd.AddParam("@2", serialized);
-
-            using (var tran = connection.BeginTransaction())
+            using (var cmd = connection.CreateCommand())
             {
-                try
+                cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
+                cmd.AddParam("@1", user.Id);
+                cmd.AddParam("@2", serialized);
+
+                using (var tran = connection.BeginTransaction())
                 {
-                    cmd.Transaction = tran;
+                    try
+                    {
+                        cmd.Transaction = tran;
 
-                    await cmd.ExecuteNonQueryAsync(cancellationToken);
+                        await cmd.ExecuteNonQueryAsync(cancellationToken);
 
-                    tran.Commit();
-                }
-                catch (OperationCanceledException)
-                {
-                    tran.Rollback();
-                }
-                catch (Exception e)
-                {
-                    Logger.ErrorException("Failed to commit transaction.", e);
-                    tran.Rollback();
+                        tran.Commit();
+                    }
+                    catch (OperationCanceledException)
+                    {
+                        tran.Rollback();
+                    }
+                    catch (Exception e)
+                    {
+                        Logger.ErrorException("Failed to commit transaction.", e);
+                        tran.Rollback();
+                    }
                 }
             }
         }
@@ -160,17 +162,19 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         /// <returns>IEnumerable{User}.</returns>
         public IEnumerable<User> RetrieveAllUsers()
         {
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "select data from users";
-
-            using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+            using (var cmd = connection.CreateCommand())
             {
-                while (reader.Read())
+                cmd.CommandText = "select data from users";
+
+                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
                 {
-                    using (var stream = GetStream(reader, 0))
+                    while (reader.Read())
                     {
-                        var user = _jsonSerializer.DeserializeFromStream<User>(stream);
-                        yield return user;
+                        using (var stream = GetStream(reader, 0))
+                        {
+                            var user = _jsonSerializer.DeserializeFromStream<User>(stream);
+                            yield return user;
+                        }
                     }
                 }
             }
@@ -197,12 +201,14 @@ namespace MediaBrowser.Server.Implementations.Sqlite
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "delete from users where guid=@guid";
-            var guidParam = cmd.Parameters.Add("@guid", DbType.Guid);
-            guidParam.Value = user.Id;
+            using (var cmd = connection.CreateCommand())
+            {
+                cmd.CommandText = "delete from users where guid=@guid";
+                var guidParam = cmd.Parameters.Add("@guid", DbType.Guid);
+                guidParam.Value = user.Id;
 
-            return ExecuteCommand(cmd);
+                return ExecuteCommand(cmd);
+            }
         }
     }
 }

+ 3 - 10
MediaBrowser.ServerApplication/LibraryExplorer.xaml.cs

@@ -175,16 +175,9 @@ namespace MediaBrowser.ServerApplication
             {
                 var item = (BaseItem)(tvwLibrary.SelectedItem as TreeViewItem).Tag;
                 lblObjType.Content = "Type: " + item.GetType().Name;
-                var trailers = item.LocalTrailers != null && item.LocalTrailers.Count > 0
-                                   ? "\nTrailers: " +
-                                     String.Join(Environment.NewLine, item.LocalTrailers.Select(t => t.Path))
-                                   : "";
+
                 var movie = item as Movie;
-                var features = movie != null && movie.SpecialFeatures != null
-                                   ? "\nSpecial Features: " +
-                                     string.Join(Environment.NewLine,
-                                                 movie.SpecialFeatures.Select(f => f.Path))
-                                   : "";
+
                 var folder = item as Folder;
                 if (folder != null)
                 {
@@ -222,7 +215,7 @@ namespace MediaBrowser.ServerApplication
                     lblIndexBy.Visibility = ddlIndexBy.Visibility = ddlSortBy.Visibility = lblSortBy.Visibility = Visibility.Hidden;
 
                 }
-                txtData.Text = FormatJson(_jsonSerializer.SerializeToString(item)) + trailers + features;
+                txtData.Text = FormatJson(_jsonSerializer.SerializeToString(item));
 
                 var previews = new List<PreviewItem>();
                 await Task.Run(() =>