diff --git a/MediaBrowser.Api/LibraryService.cs b/MediaBrowser.Api/LibraryService.cs
index c2ccf4dcdd..f1338c44b2 100644
--- a/MediaBrowser.Api/LibraryService.cs
+++ b/MediaBrowser.Api/LibraryService.cs
@@ -431,7 +431,7 @@ namespace MediaBrowser.Api
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = _itemRepo.GetItems(item.ThemeSongIds)
+            var items = _itemRepo.RetrieveItems<Audio>(item.ThemeSongIds)
                          .OrderBy(i => i.SortName)
                          .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user))
                          .Select(t => t.Result)
@@ -471,7 +471,7 @@ namespace MediaBrowser.Api
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
             var items =
-                _itemRepo.GetItems(item.ThemeVideoIds)
+                _itemRepo.RetrieveItems<Video>(item.ThemeVideoIds)
                          .OrderBy(i => i.SortName)
                          .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user))
                          .Select(t => t.Result)
diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs
index 04a18e40ed..09bdc05479 100644
--- a/MediaBrowser.Api/TvShowsService.cs
+++ b/MediaBrowser.Api/TvShowsService.cs
@@ -70,7 +70,7 @@ namespace MediaBrowser.Api
     public class GetSimilarShows : BaseGetSimilarItems
     {
     }
-    
+
     /// <summary>
     /// Class TvShowsService
     /// </summary>
@@ -110,9 +110,9 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetSimilarShows request)
         {
-            var result = SimilarItemsHelper.GetSimilarItems(_userManager, 
-                _libraryManager, 
-                _userDataRepository, 
+            var result = SimilarItemsHelper.GetSimilarItems(_userManager,
+                _libraryManager,
+                _userDataRepository,
                 Logger,
                 request, item => item is Series,
                 SimilarItemsHelper.GetSimiliarityScore);
@@ -141,20 +141,19 @@ namespace MediaBrowser.Api
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var tasks = user.RootFolder
+            var itemsArray = user.RootFolder
                 .GetRecursiveChildren(user)
                 .OfType<Series>()
                 .AsParallel()
-                .Select(i => GetNextUp(i, user));
-
-            var itemsArray = await Task.WhenAll(tasks).ConfigureAwait(false);
+                .Select(i => GetNextUp(i, user))
+                .ToArray();
 
             itemsArray = itemsArray
                 .Where(i => i.Item1 != null)
                 .OrderByDescending(i =>
                 {
                     var seriesUserData =
-                        _userDataRepository.GetUserData(user.Id, i.Item1.Series.GetUserDataKey()).Result;
+                        _userDataRepository.GetUserData(user.Id, i.Item1.Series.GetUserDataKey());
 
                     if (seriesUserData.IsFavorite)
                     {
@@ -190,7 +189,7 @@ namespace MediaBrowser.Api
         /// <param name="series">The series.</param>
         /// <param name="user">The user.</param>
         /// <returns>Task{Episode}.</returns>
-        private async Task<Tuple<Episode,DateTime>> GetNextUp(Series series, User user)
+        private Tuple<Episode, DateTime> GetNextUp(Series series, User user)
         {
             var allEpisodes = series.GetRecursiveChildren(user)
                 .OfType<Episode>()
@@ -205,7 +204,7 @@ namespace MediaBrowser.Api
             // Go back starting with the most recent episodes
             foreach (var episode in allEpisodes)
             {
-                var userData = await _userDataRepository.GetUserData(user.Id, episode.GetUserDataKey()).ConfigureAwait(false);
+                var userData = _userDataRepository.GetUserData(user.Id, episode.GetUserDataKey());
 
                 if (userData.Played)
                 {
diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
index 26b0aa1921..65ec74bcf5 100644
--- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
+++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs
@@ -337,7 +337,7 @@ namespace MediaBrowser.Api.UserLibrary
         public string Name;
 
         public BaseItem Item;
-        private Task<UserItemData> _userData;
+        private UserItemData _userData;
 
         public List<BaseItem> Items
         {
@@ -353,12 +353,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var item = await GetItem().ConfigureAwait(false);
 
-            if (_userData == null)
-            {
-                _userData = repo.GetUserData(userId, item.GetUserDataKey());
-            }
-
-            return await _userData.ConfigureAwait(false);
+            return _userData ?? (_userData = repo.GetUserData(userId, item.GetUserDataKey()));
         }
 
         public IbnStub(string name, Func<IEnumerable<BaseItem>> childItems, Func<string,Task<T>> item)
diff --git a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
index 42b76e29d9..eaa65dc2db 100644
--- a/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemByNameUserDataService.cs
@@ -240,9 +240,9 @@ namespace MediaBrowser.Api.UserLibrary
             }
 
             var key = item.GetUserDataKey();
-            
+
             // Get the user data for this item
-            var data = await UserDataRepository.GetUserData(userId, key).ConfigureAwait(false);
+            var data = UserDataRepository.GetUserData(userId, key);
 
             // Set favorite status
             data.IsFavorite = isFavorite;
@@ -288,9 +288,9 @@ namespace MediaBrowser.Api.UserLibrary
             }
 
             var key = item.GetUserDataKey();
-            
+
             // Get the user data for this item
-            var data = await UserDataRepository.GetUserData(userId, key).ConfigureAwait(false);
+            var data = UserDataRepository.GetUserData(userId, key);
 
             data.Likes = likes;
 
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index a06ac68b72..a4ed0396ef 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -335,7 +335,7 @@ namespace MediaBrowser.Api.UserLibrary
                 case ItemFilter.Likes:
                     return items.Where(item =>
                     {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
+                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
 
                         return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
                     });
@@ -343,7 +343,7 @@ namespace MediaBrowser.Api.UserLibrary
                 case ItemFilter.Dislikes:
                     return items.Where(item =>
                     {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
+                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
 
                         return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
                     });
@@ -351,7 +351,7 @@ namespace MediaBrowser.Api.UserLibrary
                 case ItemFilter.IsFavorite:
                     return items.Where(item =>
                     {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
+                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
 
                         return userdata != null && userdata.IsFavorite;
                     });
@@ -362,7 +362,7 @@ namespace MediaBrowser.Api.UserLibrary
                 case ItemFilter.IsResumable:
                     return items.Where(item =>
                     {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
+                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
 
                         return userdata != null && userdata.PlaybackPositionTicks > 0;
                     });
@@ -370,7 +370,7 @@ namespace MediaBrowser.Api.UserLibrary
                 case ItemFilter.IsPlayed:
                     return items.Where(item =>
                     {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
+                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
 
                         return userdata != null && userdata.Played;
                     });
@@ -378,7 +378,7 @@ namespace MediaBrowser.Api.UserLibrary
                 case ItemFilter.IsUnplayed:
                     return items.Where(item =>
                     {
-                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey()).Result;
+                        var userdata = repository.GetUserData(user.Id, item.GetUserDataKey());
 
                         return userdata == null || !userdata.Played;
                     });
diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
index 8c1f3b500b..786eea5b31 100644
--- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
+++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs
@@ -399,7 +399,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = _itemRepo.GetItems(movie.SpecialFeatureIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToList();
+            var items = _itemRepo.RetrieveItems<Video>(movie.SpecialFeatureIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToList();
 
             return ToOptimizedResult(items);
         }
@@ -420,7 +420,7 @@ namespace MediaBrowser.Api.UserLibrary
 
             var dtoBuilder = new DtoBuilder(Logger, _libraryManager, _userDataRepository);
 
-            var items = _itemRepo.GetItems(item.LocalTrailerIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToList();
+            var items = _itemRepo.RetrieveItems<Trailer>(item.LocalTrailerIds).OrderBy(i => i.SortName).Select(i => dtoBuilder.GetBaseItemDto(i, fields, user)).Select(t => t.Result).ToList();
 
             return ToOptimizedResult(items);
         }
@@ -496,7 +496,7 @@ namespace MediaBrowser.Api.UserLibrary
             // Get the user data for this item
             var key = item.GetUserDataKey();
 
-            var data = _userDataRepository.GetUserData(user.Id, key).Result;
+            var data = _userDataRepository.GetUserData(user.Id, key);
 
             // Set favorite status
             data.IsFavorite = true;
@@ -519,7 +519,7 @@ namespace MediaBrowser.Api.UserLibrary
             var key = item.GetUserDataKey();
 
             // Get the user data for this item
-            var data = _userDataRepository.GetUserData(user.Id, key).Result;
+            var data = _userDataRepository.GetUserData(user.Id, key);
 
             // Set favorite status
             data.IsFavorite = false;
@@ -542,7 +542,7 @@ namespace MediaBrowser.Api.UserLibrary
             var key = item.GetUserDataKey();
 
             // Get the user data for this item
-            var data = _userDataRepository.GetUserData(user.Id, key).Result;
+            var data = _userDataRepository.GetUserData(user.Id, key);
 
             data.Rating = null;
 
@@ -564,7 +564,7 @@ namespace MediaBrowser.Api.UserLibrary
             var key = item.GetUserDataKey();
 
             // Get the user data for this item
-            var data = _userDataRepository.GetUserData(user.Id, key).Result;
+            var data = _userDataRepository.GetUserData(user.Id, key);
 
             data.Likes = request.Likes;
 
diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs
index d2b58dc968..3c74a42889 100644
--- a/MediaBrowser.Api/VideosService.cs
+++ b/MediaBrowser.Api/VideosService.cs
@@ -64,7 +64,7 @@ namespace MediaBrowser.Api
 
             var video = (Video)item;
 
-            var items = _itemRepo.GetItems(video.AdditionalPartIds)
+            var items = _itemRepo.RetrieveItems<Video>(video.AdditionalPartIds)
                          .OrderBy(i => i.SortName)
                          .Select(i => dtoBuilder.GetBaseItemDto(i, fields, user))
                          .Select(t => t.Result)
diff --git a/MediaBrowser.Controller/Dto/DtoBuilder.cs b/MediaBrowser.Controller/Dto/DtoBuilder.cs
index 7fd188acb5..1e0e5286fa 100644
--- a/MediaBrowser.Controller/Dto/DtoBuilder.cs
+++ b/MediaBrowser.Controller/Dto/DtoBuilder.cs
@@ -73,11 +73,6 @@ namespace MediaBrowser.Controller.Dto
                 tasks.Add(AttachPeople(dto, item));
             }
 
-            if (user != null)
-            {
-                tasks.Add(AttachUserSpecificInfo(dto, item, user, fields));
-            }
-
             if (fields.Contains(ItemFields.PrimaryImageAspectRatio))
             {
                 try
@@ -91,6 +86,11 @@ namespace MediaBrowser.Controller.Dto
                 }
             }
 
+            if (user != null)
+            {
+                AttachUserSpecificInfo(dto, item, user, fields);
+            }
+
             AttachBasicFields(dto, item, fields);
 
             // Make sure all the tasks we kicked off have completed.
@@ -109,7 +109,7 @@ namespace MediaBrowser.Controller.Dto
         /// <param name="item">The item.</param>
         /// <param name="user">The user.</param>
         /// <param name="fields">The fields.</param>
-        private async Task AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields)
+        private void AttachUserSpecificInfo(BaseItemDto dto, BaseItem item, User user, List<ItemFields> fields)
         {
             if (item.IsFolder && fields.Contains(ItemFields.DisplayPreferencesId))
             {
@@ -127,13 +127,13 @@ namespace MediaBrowser.Controller.Dto
                     // Skip sorting since all we want is a count
                     dto.ChildCount = folder.GetChildren(user).Count();
 
-                    await SetSpecialCounts(folder, user, dto, _userDataRepository).ConfigureAwait(false);
+                    SetSpecialCounts(folder, user, dto, _userDataRepository);
                 }
             }
 
             if (addUserData)
             {
-                var userData = await _userDataRepository.GetUserData(user.Id, item.GetUserDataKey()).ConfigureAwait(false);
+                var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey());
 
                 dto.UserData = GetUserItemDataDto(userData);
 
@@ -529,7 +529,7 @@ namespace MediaBrowser.Controller.Dto
         /// <param name="dto">The dto.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <returns>Task.</returns>
-        private static async Task SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserDataRepository userDataRepository)
+        private static void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, IUserDataRepository userDataRepository)
         {
             var rcentlyAddedItemCount = 0;
             var recursiveItemCount = 0;
@@ -540,7 +540,7 @@ namespace MediaBrowser.Controller.Dto
             // Loop through each recursive child
             foreach (var child in folder.GetRecursiveChildren(user).Where(i => !i.IsFolder).ToList())
             {
-                var userdata = await userDataRepository.GetUserData(user.Id, child.GetUserDataKey()).ConfigureAwait(false);
+                var userdata = userDataRepository.GetUserData(user.Id, child.GetUserDataKey());
 
                 recursiveItemCount++;
 
@@ -767,7 +767,7 @@ namespace MediaBrowser.Controller.Dto
         {
             if (data == null)
             {
-                throw new ArgumentNullException();
+                throw new ArgumentNullException("data");
             }
 
             return new UserItemDataDto
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 6ae465aa7e..2850d7092a 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -273,7 +273,7 @@ namespace MediaBrowser.Controller.Entities
             {
                 return Guid.Empty;
             }
-            
+
             try
             {
                 if (!ResolveArgs.IsDirectory)
@@ -681,11 +681,6 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>List{Video}.</returns>
         private IEnumerable<Trailer> LoadLocalTrailers()
         {
-            if (LocationType != LocationType.FileSystem)
-            {
-                return new List<Trailer>();
-            }
-
             ItemResolveArgs resolveArgs;
 
             try
@@ -737,7 +732,7 @@ namespace MediaBrowser.Controller.Entities
             return LibraryManager.ResolvePaths<Trailer>(files, null).Select(video =>
             {
                 // Try to retrieve it from the db. If we don't find it, use the resolved version
-                var dbItem = LibraryManager.RetrieveItem(video.Id) as Trailer;
+                var dbItem = LibraryManager.RetrieveItem(video.Id, typeof(Trailer)) as Trailer;
 
                 if (dbItem != null)
                 {
@@ -756,11 +751,6 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>List{Audio.Audio}.</returns>
         private IEnumerable<Audio.Audio> LoadThemeSongs()
         {
-            if (LocationType != LocationType.FileSystem)
-            {
-                return new List<Audio.Audio>();
-            }
-
             ItemResolveArgs resolveArgs;
 
             try
@@ -803,7 +793,7 @@ namespace MediaBrowser.Controller.Entities
             return LibraryManager.ResolvePaths<Audio.Audio>(files, null).Select(audio =>
             {
                 // Try to retrieve it from the db. If we don't find it, use the resolved version
-                var dbItem = LibraryManager.RetrieveItem(audio.Id) as Audio.Audio;
+                var dbItem = LibraryManager.RetrieveItem(audio.Id, typeof(Audio.Audio)) as Audio.Audio;
 
                 if (dbItem != null)
                 {
@@ -821,11 +811,6 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>List{Video}.</returns>
         private IEnumerable<Video> LoadThemeVideos()
         {
-            if (LocationType != LocationType.FileSystem)
-            {
-                return new List<Video>();
-            }
-
             ItemResolveArgs resolveArgs;
 
             try
@@ -866,7 +851,7 @@ namespace MediaBrowser.Controller.Entities
             return LibraryManager.ResolvePaths<Video>(files, null).Select(item =>
             {
                 // Try to retrieve it from the db. If we don't find it, use the resolved version
-                var dbItem = LibraryManager.RetrieveItem(item.Id) as Video;
+                var dbItem = LibraryManager.RetrieveItem(item.Id, typeof(Video)) as Video;
 
                 if (dbItem != null)
                 {
@@ -896,13 +881,20 @@ namespace MediaBrowser.Controller.Entities
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var themeSongsChanged = await RefreshThemeSongs(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+            var themeSongsChanged = false;
 
-            var themeVideosChanged = await RefreshThemeVideos(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+            var themeVideosChanged = false;
 
-            var localTrailersChanged = await RefreshLocalTrailers(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+            var localTrailersChanged = false;
 
-            cancellationToken.ThrowIfCancellationRequested();
+            if (LocationType == LocationType.FileSystem && Parent != null)
+            {
+                themeSongsChanged = await RefreshThemeSongs(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+
+                themeVideosChanged = await RefreshThemeVideos(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+
+                localTrailersChanged = await RefreshLocalTrailers(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+            }
 
             cancellationToken.ThrowIfCancellationRequested();
 
@@ -1096,8 +1088,7 @@ namespace MediaBrowser.Controller.Entities
                 parent = parent.Parent;
             }
 
-            //not found - load from repo
-            return LibraryManager.RetrieveItem(id);
+            return null;
         }
 
         /// <summary>
@@ -1315,7 +1306,7 @@ namespace MediaBrowser.Controller.Entities
 
             var key = GetUserDataKey();
 
-            var data = await userManager.GetUserData(user.Id, key).ConfigureAwait(false);
+            var data = userManager.GetUserData(user.Id, key);
 
             if (wasPlayed)
             {
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index ce36366b43..de965221b8 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Common.Progress;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Reflection;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Model.Entities;
 using System;
@@ -21,6 +22,15 @@ namespace MediaBrowser.Controller.Entities
     /// </summary>
     public class Folder : BaseItem
     {
+        private static TypeMapper _typeMapper = new TypeMapper();
+
+        public Folder()
+        {
+            ChildDefinitions = new ConcurrentDictionary<Guid, string>();
+        }
+
+        public ConcurrentDictionary<Guid, string> ChildDefinitions { get; set; }
+
         /// <summary>
         /// Gets a value indicating whether this instance is folder.
         /// </summary>
@@ -108,16 +118,14 @@ namespace MediaBrowser.Controller.Entities
                 item.DateModified = DateTime.Now;
             }
 
-            if (!_children.TryAdd(item.Id, item))
+            if (!_children.TryAdd(item.Id, item) || !ChildDefinitions.TryAdd(item.Id, item.GetType().FullName))
             {
                 throw new InvalidOperationException("Unable to add " + item.Name);
             }
 
-            var newChildren = Children.ToList();
-
             await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
 
-            await LibraryManager.SaveChildren(Id, newChildren, cancellationToken).ConfigureAwait(false);
+            await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false);
         }
 
         /// <summary>
@@ -145,19 +153,18 @@ namespace MediaBrowser.Controller.Entities
         public Task RemoveChild(BaseItem item, CancellationToken cancellationToken)
         {
             BaseItem removed;
+            string removedType;
 
-            if (!_children.TryRemove(item.Id, out removed))
+            if (!_children.TryRemove(item.Id, out removed) || !ChildDefinitions.TryRemove(item.Id, out removedType))
             {
                 throw new InvalidOperationException("Unable to remove " + item.Name);
             }
 
             item.Parent = null;
             
-            var newChildren = Children.ToList();
-
             LibraryManager.ReportItemRemoved(item);
 
-            return LibraryManager.SaveChildren(Id, newChildren, cancellationToken);
+            return LibraryManager.UpdateItem(this, cancellationToken);
         }
 
         #region Indexing
@@ -652,7 +659,7 @@ namespace MediaBrowser.Controller.Entities
 
             var options = new ParallelOptions
             {
-                MaxDegreeOfParallelism = 50
+                MaxDegreeOfParallelism = 20
             };
 
             Parallel.ForEach(nonCachedChildren, options, child =>
@@ -702,6 +709,9 @@ namespace MediaBrowser.Controller.Entities
                     }
                     else
                     {
+                        string removedType;
+                        ChildDefinitions.TryRemove(item.Id, out removedType);
+
                         LibraryManager.ReportItemRemoved(item);
                     }
                 }
@@ -716,11 +726,13 @@ namespace MediaBrowser.Controller.Entities
                     }
                     else
                     {
+                        ChildDefinitions.TryAdd(item.Id, item.GetType().FullName);
+                        
                         Logger.Debug("** " + item.Name + " Added to library.");
                     }
                 }
 
-                await LibraryManager.SaveChildren(Id, newChildren, CancellationToken.None).ConfigureAwait(false);
+                await LibraryManager.UpdateItem(this, CancellationToken.None).ConfigureAwait(false);
 
                 //force the indexes to rebuild next time
                 IndexCache.Clear();
@@ -848,9 +860,38 @@ namespace MediaBrowser.Controller.Entities
         /// Get our children from the repo - stubbed for now
         /// </summary>
         /// <returns>IEnumerable{BaseItem}.</returns>
-        protected virtual IEnumerable<BaseItem> GetCachedChildren()
+        protected IEnumerable<BaseItem> GetCachedChildren()
+        {
+            var items = ChildDefinitions.ToList().Select(RetrieveChild).Where(i => i != null).ToList();
+
+            foreach (var item in items)
+            {
+                item.Parent = this;
+            }
+
+            return items;
+        }
+
+        /// <summary>
+        /// Retrieves the child.
+        /// </summary>
+        /// <param name="child">The child.</param>
+        /// <returns>BaseItem.</returns>
+        private BaseItem RetrieveChild(KeyValuePair<Guid,string> child)
         {
-            return LibraryManager.RetrieveChildren(this).Select(i => i is IByReferenceItem ? LibraryManager.GetOrAddByReferenceItem(i) : i);
+            var type = child.Value;
+
+            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);
+                return null;
+            }
+
+            var item = LibraryManager.RetrieveItem(child.Key, itemType);
+
+            return item is IByReferenceItem ? LibraryManager.GetOrAddByReferenceItem(item) : item;
         }
 
         /// <summary>
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index 307fe19544..6e649fd656 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -68,7 +68,14 @@ namespace MediaBrowser.Controller.Entities.Movies
             // Kick off a task to refresh the main item
             var result = await base.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
 
-            var specialFeaturesChanged = await RefreshSpecialFeatures(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+            var specialFeaturesChanged = false;
+
+            // Must have a parent to have special features
+            // In other words, it must be part of the Parent/Child tree
+            if (LocationType == LocationType.FileSystem && Parent != null)
+            {
+                specialFeaturesChanged = await RefreshSpecialFeatures(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
+            }
 
             return specialFeaturesChanged || result;
         }
@@ -95,11 +102,6 @@ namespace MediaBrowser.Controller.Entities.Movies
         /// <returns>IEnumerable{Video}.</returns>
         private IEnumerable<Video> LoadSpecialFeatures()
         {
-            if (LocationType != LocationType.FileSystem)
-            {
-                return new List<Video>();
-            }
-
             FileSystemInfo folder;
 
             try
@@ -133,7 +135,7 @@ namespace MediaBrowser.Controller.Entities.Movies
             return LibraryManager.ResolvePaths<Video>(files, null).Select(video =>
             {
                 // Try to retrieve it from the db. If we don't find it, use the resolved version
-                var dbItem = LibraryManager.RetrieveItem(video.Id) as Video;
+                var dbItem = LibraryManager.RetrieveItem(video.Id, typeof(Video)) as Video;
 
                 if (dbItem != null)
                 {
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index ad4cb2d09d..ee717a1918 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -139,7 +139,10 @@ namespace MediaBrowser.Controller.Entities
 
             var additionalPartsChanged = false;
 
-            if (IsMultiPart && LocationType == LocationType.FileSystem)
+            // Must have a parent to have additional parts
+            // In other words, it must be part of the Parent/Child tree
+            // The additional parts won't have additional parts themselves
+            if (IsMultiPart && LocationType == LocationType.FileSystem && Parent != null)
             {
                 try
                 {
@@ -164,11 +167,6 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>Task{System.Boolean}.</returns>
         private async Task<bool> RefreshAdditionalParts(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
         {
-            if (!IsMultiPart || LocationType != LocationType.FileSystem)
-            {
-                return false;
-            }
-
             var newItems = LoadAdditionalParts().ToList();
 
             var newItemIds = newItems.Select(i => i.Id).ToList();
@@ -214,7 +212,7 @@ namespace MediaBrowser.Controller.Entities
             return LibraryManager.ResolvePaths<Video>(files, null).Select(video =>
             {
                 // Try to retrieve it from the db. If we don't find it, use the resolved version
-                var dbItem = LibraryManager.RetrieveItem(video.Id) as Video;
+                var dbItem = LibraryManager.RetrieveItem(video.Id, typeof(Video)) as Video;
 
                 if (dbItem != null)
                 {
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 7e84350b37..6d6fab3bea 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -216,24 +216,9 @@ namespace MediaBrowser.Controller.Library
         /// Retrieves the item.
         /// </summary>
         /// <param name="id">The id.</param>
-        /// <returns>Task{BaseItem}.</returns>
-        BaseItem RetrieveItem(Guid id);
-
-        /// <summary>
-        /// Saves the children.
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="children">The children.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        Task SaveChildren(Guid id, IEnumerable<BaseItem> children, CancellationToken cancellationToken);
-
-        /// <summary>
-        /// Retrieves the children.
-        /// </summary>
-        /// <param name="parent">The parent.</param>
-        /// <returns>IEnumerable{BaseItem}.</returns>
-        IEnumerable<BaseItem> RetrieveChildren(Folder parent);
+        /// <param name="type">The type.</param>
+        /// <returns>BaseItem.</returns>
+        BaseItem RetrieveItem(Guid id, Type type);
 
         /// <summary>
         /// Validates the artists.
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index ba9e9f5bde..8765998f38 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -80,6 +80,7 @@
     <Compile Include="Library\ILibraryPrescanTask.cs" />
     <Compile Include="Library\IMetadataSaver.cs" />
     <Compile Include="Localization\ILocalizationManager.cs" />
+    <Compile Include="Reflection\TypeMapper.cs" />
     <Compile Include="Session\ISessionManager.cs" />
     <Compile Include="Drawing\ImageExtensions.cs" />
     <Compile Include="Drawing\ImageHeader.cs" />
diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs
index bf3bc626af..d854d0e207 100644
--- a/MediaBrowser.Controller/Persistence/IItemRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs
@@ -1,9 +1,10 @@
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Controller.Persistence
 {
@@ -20,36 +21,6 @@ namespace MediaBrowser.Controller.Persistence
         /// <returns>Task.</returns>
         Task SaveItem(BaseItem item, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// Gets an item
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <returns>BaseItem.</returns>
-        BaseItem GetItem(Guid id);
-
-        /// <summary>
-        /// Gets children of a given Folder
-        /// </summary>
-        /// <param name="parent">The parent.</param>
-        /// <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>
-        /// <param name="parentId">The parent id.</param>
-        /// <param name="children">The children.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        Task SaveChildren(Guid parentId, IEnumerable<BaseItem> children, CancellationToken cancellationToken);
-
         /// <summary>
         /// Gets the critic reviews.
         /// </summary>
@@ -72,5 +43,46 @@ namespace MediaBrowser.Controller.Persistence
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         Task SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Retrieves the item.
+        /// </summary>
+        /// <param name="id">The id.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>BaseItem.</returns>
+        BaseItem RetrieveItem(Guid id, Type type);
+    }
+
+    /// <summary>
+    /// Class ItemRepositoryExtensions
+    /// </summary>
+    public static class ItemRepositoryExtensions
+    {
+        /// <summary>
+        /// Retrieves the item.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="repository">The repository.</param>
+        /// <param name="id">The id.</param>
+        /// <returns>``0.</returns>
+        public static T RetrieveItem<T>(this IItemRepository repository, Guid id) 
+            where T : BaseItem, new()
+        {
+            return repository.RetrieveItem(id, typeof(T)) as T;
+        }
+
+        /// <summary>
+        /// Retrieves the item.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="repository">The repository.</param>
+        /// <param name="idList">The id list.</param>
+        /// <returns>IEnumerable{``0}.</returns>
+        public static IEnumerable<T> RetrieveItems<T>(this IItemRepository repository, IEnumerable<Guid> idList) 
+            where T : BaseItem, new()
+        {
+            return idList.Select(repository.RetrieveItem<T>).Where(i => i != null);
+        }
     }
 }
+
diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
index 1b4efc58b1..ad111f4ed4 100644
--- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
+++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs
@@ -27,6 +27,6 @@ namespace MediaBrowser.Controller.Persistence
         /// <param name="userId">The user id.</param>
         /// <param name="key">The key.</param>
         /// <returns>Task{UserItemData}.</returns>
-        Task<UserItemData> GetUserData(Guid userId, string key);
+        UserItemData GetUserData(Guid userId, string key);
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Reflection/TypeMapper.cs b/MediaBrowser.Controller/Reflection/TypeMapper.cs
similarity index 96%
rename from MediaBrowser.Server.Implementations/Reflection/TypeMapper.cs
rename to MediaBrowser.Controller/Reflection/TypeMapper.cs
index 5f411a0023..d968a3b420 100644
--- a/MediaBrowser.Server.Implementations/Reflection/TypeMapper.cs
+++ b/MediaBrowser.Controller/Reflection/TypeMapper.cs
@@ -2,7 +2,7 @@
 using System.Collections.Concurrent;
 using System.Linq;
 
-namespace MediaBrowser.Server.Implementations.Reflection
+namespace MediaBrowser.Controller.Reflection
 {
     /// <summary>
     /// Class TypeMapper
diff --git a/MediaBrowser.Model/Entities/IHasProviderIds.cs b/MediaBrowser.Model/Entities/IHasProviderIds.cs
index 2ddf8ffad1..1c54455da6 100644
--- a/MediaBrowser.Model/Entities/IHasProviderIds.cs
+++ b/MediaBrowser.Model/Entities/IHasProviderIds.cs
@@ -39,6 +39,11 @@ namespace MediaBrowser.Model.Entities
         /// <returns>System.String.</returns>
         public static string GetProviderId(this IHasProviderIds instance, string name)
         {
+            if (instance == null)
+            {
+                throw new ArgumentNullException("instance");
+            }
+
             if (instance.ProviderIds == null)
             {
                 return null;
@@ -57,6 +62,11 @@ namespace MediaBrowser.Model.Entities
         /// <param name="value">The value.</param>
         public static void SetProviderId(this IHasProviderIds instance, string name, string value)
         {
+            if (instance == null)
+            {
+                throw new ArgumentNullException("instance");
+            }
+            
             // If it's null remove the key from the dictionary
             if (string.IsNullOrEmpty(value))
             {
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 29a85dd9c0..f8aa4e2728 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -78,6 +78,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Savers\MovieXmlSaver.cs" />
     <Compile Include="TV\EpisodeImageFromMediaLocationProvider.cs" />
+    <Compile Include="TV\EpisodeIndexNumberProvider.cs" />
     <Compile Include="TV\EpisodeProviderFromXml.cs" />
     <Compile Include="TV\EpisodeXmlParser.cs" />
     <Compile Include="TV\FanArtSeasonProvider.cs" />
diff --git a/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs
index 99d1cdbc1e..9e3a468c6c 100644
--- a/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/BaseFFProbeProvider.cs
@@ -41,7 +41,7 @@ namespace MediaBrowser.Providers.MediaInfo
         }
 
         protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-        
+
         /// <summary>
         /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
         /// </summary>
@@ -134,7 +134,7 @@ namespace MediaBrowser.Providers.MediaInfo
         /// <param name="mount">The mount.</param>
         protected virtual void OnPreFetch(T item, IIsoMount mount)
         {
-            
+
         }
 
         /// <summary>
@@ -187,12 +187,16 @@ namespace MediaBrowser.Providers.MediaInfo
             var stream = new MediaStream
             {
                 Codec = streamInfo.codec_name,
-                Language = GetDictionaryValue(streamInfo.tags, "language"),
                 Profile = streamInfo.profile,
                 Level = streamInfo.level,
                 Index = streamInfo.index
             };
 
+            if (streamInfo.tags != null)
+            {
+                stream.Language = GetDictionaryValue(streamInfo.tags, "language");
+            }
+
             if (streamInfo.codec_type.Equals("audio", StringComparison.OrdinalIgnoreCase))
             {
                 stream.Type = MediaStreamType.Audio;
diff --git a/MediaBrowser.Providers/TV/EpisodeIndexNumberProvider.cs b/MediaBrowser.Providers/TV/EpisodeIndexNumberProvider.cs
new file mode 100644
index 0000000000..aa59ff7cf9
--- /dev/null
+++ b/MediaBrowser.Providers/TV/EpisodeIndexNumberProvider.cs
@@ -0,0 +1,67 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.TV
+{
+    /// <summary>
+    /// Making this a provider because of how slow it is
+    /// It only ever needs to run once
+    /// </summary>
+    public class EpisodeIndexNumberProvider : BaseMetadataProvider
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class.
+        /// </summary>
+        /// <param name="logManager">The log manager.</param>
+        /// <param name="configurationManager">The configuration manager.</param>
+        public EpisodeIndexNumberProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
+            : base(logManager, configurationManager)
+        {
+        }
+
+        /// <summary>
+        /// Supportses the specified item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
+        public override bool Supports(BaseItem item)
+        {
+            return item is Episode;
+        }
+
+        /// <summary>
+        /// Fetches metadata and returns true or false indicating if any work that requires persistence was done
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="force">if set to <c>true</c> [force].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{System.Boolean}.</returns>
+        public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
+        {
+            var episode = (Episode)item;
+
+            episode.IndexNumber = TVUtils.GetEpisodeNumberFromFile(item.Path, item.Parent is Season);
+            episode.IndexNumberEnd = TVUtils.GetEndingEpisodeNumberFromFile(item.Path);
+
+            SetLastRefreshed(item, DateTime.UtcNow);
+
+            return TrueTaskResult;
+        }
+
+        /// <summary>
+        /// Gets the priority.
+        /// </summary>
+        /// <value>The priority.</value>
+        public override MetadataProviderPriority Priority
+        {
+            get { return MetadataProviderPriority.First; }
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index f4d0f9c505..e174b9a23d 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -564,7 +564,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 Directory.CreateDirectory(rootFolderPath);
             }
 
-            var rootFolder = RetrieveItem(rootFolderPath.GetMBId(typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath));
+            var rootFolder = RetrieveItem(rootFolderPath.GetMBId(typeof(AggregateFolder)), typeof(AggregateFolder)) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath));
 
             // Add in the plug-in folders
             foreach (var child in PluginFolderCreators)
@@ -589,7 +589,8 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>UserRootFolder.</returns>
         public UserRootFolder GetUserRootFolder(string userRootPath)
         {
-            return _userRootFolders.GetOrAdd(userRootPath, key => RetrieveItem(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)));
+            return _userRootFolders.GetOrAdd(userRootPath, key => RetrieveItem(userRootPath.GetMBId(typeof(UserRootFolder)), typeof(UserRootFolder)) as UserRootFolder ?? 
+                (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)));
         }
 
         /// <summary>
@@ -779,9 +780,11 @@ namespace MediaBrowser.Server.Implementations.Library
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            var id = path.GetMBId(typeof(T));
+            var type = typeof(T);
 
-            var item = RetrieveItem(id) as T;
+            var id = path.GetMBId(type);
+
+            var item = RetrieveItem(id, type) as T;
             if (item == null)
             {
                 item = new T
@@ -816,7 +819,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            const int maxTasks = 10;
+            const int maxTasks = 15;
 
             var tasks = new List<Task>();
 
@@ -1166,7 +1169,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 return item;
             }
 
-            return ItemRepository.GetItem(id);
+            return null;
         }
 
         /// <summary>
@@ -1340,39 +1343,11 @@ namespace MediaBrowser.Server.Implementations.Library
         /// Retrieves the item.
         /// </summary>
         /// <param name="id">The id.</param>
-        /// <returns>Task{BaseItem}.</returns>
-        public BaseItem RetrieveItem(Guid id)
-        {
-            return ItemRepository.GetItem(id);
-        }
-
-        /// <summary>
-        /// Saves the children.
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="children">The children.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        public Task SaveChildren(Guid id, IEnumerable<BaseItem> children, CancellationToken cancellationToken)
-        {
-            return ItemRepository.SaveChildren(id, children, cancellationToken);
-        }
-
-        /// <summary>
-        /// Retrieves the children.
-        /// </summary>
-        /// <param name="parent">The parent.</param>
-        /// <returns>IEnumerable{BaseItem}.</returns>
-        public IEnumerable<BaseItem> RetrieveChildren(Folder parent)
+        /// <param name="type">The type.</param>
+        /// <returns>BaseItem.</returns>
+        public BaseItem RetrieveItem(Guid id, Type type)
         {
-            var children = ItemRepository.RetrieveChildren(parent).ToList();
-
-            foreach (var child in children)
-            {
-                child.Parent = parent;
-            }
-
-            return children;
+            return ItemRepository.RetrieveItem(id, type);
         }
 
         /// <summary>
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 3969acac78..84d57b9725 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -51,9 +51,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
 
                 if (episode != null)
                 {
-                    episode.IndexNumber = TVUtils.GetEpisodeNumberFromFile(args.Path, season != null);
-                    episode.IndexNumberEnd = TVUtils.GetEndingEpisodeNumberFromFile(args.Path);
-
                     if (season != null)
                     {
                         episode.ParentIndexNumber = season.IndexNumber;
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index a006161d49..a3a5220a05 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -82,14 +82,6 @@
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Data.SQLite, Version=1.0.86.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\System.Data.SQLite.x86.1.0.86.0\lib\net45\System.Data.SQLite.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Data.SQLite.Linq, Version=1.0.86.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\System.Data.SQLite.x86.1.0.86.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
-    </Reference>
     <Reference Include="System.Reactive.Core">
       <HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
     </Reference>
@@ -142,7 +134,6 @@
     <Compile Include="MediaEncoder\MediaEncoder.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Providers\ProviderManager.cs" />
-    <Compile Include="Reflection\TypeMapper.cs" />
     <Compile Include="ScheduledTasks\ArtistValidationTask.cs" />
     <Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
     <Compile Include="ScheduledTasks\ChapterImagesTask.cs" />
@@ -171,12 +162,10 @@
     <Compile Include="Sorting\RevenueComparer.cs" />
     <Compile Include="Sorting\RuntimeComparer.cs" />
     <Compile Include="Sorting\SortNameComparer.cs" />
-    <Compile Include="Sqlite\SQLiteDisplayPreferencesRepository.cs" />
-    <Compile Include="Sqlite\SQLiteExtensions.cs" />
-    <Compile Include="Sqlite\SQLiteItemRepository.cs" />
-    <Compile Include="Sqlite\SQLiteRepository.cs" />
-    <Compile Include="Sqlite\SQLiteUserDataRepository.cs" />
-    <Compile Include="Sqlite\SQLiteUserRepository.cs" />
+    <Compile Include="Persistence\JsonDisplayPreferencesRepository.cs" />
+    <Compile Include="Persistence\JsonItemRepository.cs" />
+    <Compile Include="Persistence\JsonUserDataRepository.cs" />
+    <Compile Include="Persistence\JsonUserRepository.cs" />
     <Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
     <Compile Include="Udp\UdpServer.cs" />
     <Compile Include="Updates\InstallationManager.cs" />
diff --git a/MediaBrowser.Server.Implementations/Persistence/JsonDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/JsonDisplayPreferencesRepository.cs
new file mode 100644
index 0000000000..6ac2ff07a6
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/JsonDisplayPreferencesRepository.cs
@@ -0,0 +1,164 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Concurrent;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+    public class JsonDisplayPreferencesRepository : IDisplayPreferencesRepository
+    {
+        private readonly ConcurrentDictionary<string, SemaphoreSlim> _fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
+
+        private SemaphoreSlim GetLock(string filename)
+        {
+            return _fileLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+        }
+
+        /// <summary>
+        /// Gets the name of the repository
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get
+            {
+                return "Json";
+            }
+        }
+
+        /// <summary>
+        /// The _json serializer
+        /// </summary>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        private readonly string _dataPath;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="JsonUserDataRepository" /> class.
+        /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="logManager">The log manager.</param>
+        /// <exception cref="System.ArgumentNullException">
+        /// jsonSerializer
+        /// or
+        /// appPaths
+        /// </exception>
+        public JsonDisplayPreferencesRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+        {
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+
+            _jsonSerializer = jsonSerializer;
+            _dataPath = Path.Combine(appPaths.DataPath, "display-preferences");
+        }
+
+        /// <summary>
+        /// Opens the connection to the database
+        /// </summary>
+        /// <returns>Task.</returns>
+        public Task Initialize()
+        {
+            return Task.FromResult(true);
+        }
+
+        /// <summary>
+        /// Save the display preferences associated with an item in the repo
+        /// </summary>
+        /// <param name="displayPreferences">The display preferences.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.ArgumentNullException">item</exception>
+        public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, CancellationToken cancellationToken)
+        {
+            if (displayPreferences == null)
+            {
+                throw new ArgumentNullException("displayPreferences");
+            }
+            if (displayPreferences.Id == Guid.Empty)
+            {
+                throw new ArgumentNullException("displayPreferences.Id");
+            }
+            if (cancellationToken == null)
+            {
+                throw new ArgumentNullException("cancellationToken");
+            }
+
+            cancellationToken.ThrowIfCancellationRequested();
+
+            if (!Directory.Exists(_dataPath))
+            {
+                Directory.CreateDirectory(_dataPath);
+            }
+
+            var path = Path.Combine(_dataPath, displayPreferences.Id + ".json");
+
+            var semaphore = GetLock(path);
+
+            await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+            try
+            {
+                _jsonSerializer.SerializeToFile(displayPreferences, path);
+            }
+            finally
+            {
+                semaphore.Release();
+            }
+        }
+
+        /// <summary>
+        /// Gets the display preferences.
+        /// </summary>
+        /// <param name="displayPreferencesId">The display preferences id.</param>
+        /// <returns>Task{DisplayPreferences}.</returns>
+        /// <exception cref="System.ArgumentNullException">item</exception>
+        public Task<DisplayPreferences> GetDisplayPreferences(Guid displayPreferencesId)
+        {
+            if (displayPreferencesId == Guid.Empty)
+            {
+                throw new ArgumentNullException("displayPreferencesId");
+            }
+
+            return Task.Run(() =>
+            {
+                var path = Path.Combine(_dataPath, displayPreferencesId + ".json");
+
+                try
+                {
+                    return _jsonSerializer.DeserializeFromFile<DisplayPreferences>(path);
+                }
+                catch (IOException)
+                {
+                    // File doesn't exist or is currently bring written to
+                    return null;
+                }
+            });
+        }
+
+        public void Dispose()
+        {
+            // Wait up to two seconds for any existing writes to finish
+            var locks = _fileLocks.Values.ToList()
+                                  .Where(i => i.CurrentCount == 1)
+                                  .Select(i => i.WaitAsync(2000));
+
+            var task = Task.WhenAll(locks);
+
+            Task.WaitAll(task);
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Persistence/JsonItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/JsonItemRepository.cs
new file mode 100644
index 0000000000..d0333e334e
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/JsonItemRepository.cs
@@ -0,0 +1,235 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+    public class JsonItemRepository : IItemRepository
+    {
+        private readonly ConcurrentDictionary<string, SemaphoreSlim> _fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
+
+        private SemaphoreSlim GetLock(string filename)
+        {
+            return _fileLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+        }
+        
+        /// <summary>
+        /// Gets the name of the repository
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get
+            {
+                return "Json";
+            }
+        }
+
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        private readonly string _criticReviewsPath;
+
+        private readonly FileSystemRepository _itemRepo;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="JsonUserDataRepository" /> class.
+        /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="logManager">The log manager.</param>
+        /// <exception cref="System.ArgumentNullException">appPaths</exception>
+        public JsonItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+        {
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _jsonSerializer = jsonSerializer;
+
+            _criticReviewsPath = Path.Combine(appPaths.DataPath, "critic-reviews");
+
+            _itemRepo = new FileSystemRepository(Path.Combine(appPaths.DataPath, "library"));
+        }
+
+        /// <summary>
+        /// Opens the connection to the database
+        /// </summary>
+        /// <returns>Task.</returns>
+        public Task Initialize()
+        {
+            return Task.FromResult(true);
+        }
+
+        /// <summary>
+        /// Save a standard item in the repo
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.ArgumentNullException">item</exception>
+        public async Task SaveItem(BaseItem item, CancellationToken cancellationToken)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+
+            if (!Directory.Exists(_criticReviewsPath))
+            {
+                Directory.CreateDirectory(_criticReviewsPath);
+            }
+
+            var path = _itemRepo.GetResourcePath(item.Id + ".json");
+
+            var parentPath = Path.GetDirectoryName(path);
+            if (!Directory.Exists(parentPath))
+            {
+                Directory.CreateDirectory(parentPath);
+            }
+
+            var semaphore = GetLock(path);
+
+            await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+            try
+            {
+                _jsonSerializer.SerializeToFile(item, path);
+            }
+            finally
+            {
+                semaphore.Release();
+            }
+        }
+
+        /// <summary>
+        /// Saves the items.
+        /// </summary>
+        /// <param name="items">The items.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.ArgumentNullException">
+        /// items
+        /// or
+        /// cancellationToken
+        /// </exception>
+        public Task SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
+        {
+            if (items == null)
+            {
+                throw new ArgumentNullException("items");
+            }
+
+            if (cancellationToken == null)
+            {
+                throw new ArgumentNullException("cancellationToken");
+            }
+
+            var tasks = items.Select(i => SaveItem(i, cancellationToken));
+
+            return Task.WhenAll(tasks);
+        }
+
+        /// <summary>
+        /// Retrieves the item.
+        /// </summary>
+        /// <param name="id">The id.</param>
+        /// <param name="type">The type.</param>
+        /// <returns>BaseItem.</returns>
+        /// <exception cref="System.ArgumentNullException">id</exception>
+        public BaseItem RetrieveItem(Guid id, Type type)
+        {
+            if (id == Guid.Empty)
+            {
+                throw new ArgumentNullException("id");
+            }
+
+            var path = _itemRepo.GetResourcePath(id + ".json");
+
+            try
+            {
+                return (BaseItem)_jsonSerializer.DeserializeFromFile(type, path);
+            }
+            catch (IOException)
+            {
+                // File doesn't exist or is currently bring written to
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Gets the critic reviews.
+        /// </summary>
+        /// <param name="itemId">The item id.</param>
+        /// <returns>Task{IEnumerable{ItemReview}}.</returns>
+        public Task<IEnumerable<ItemReview>> GetCriticReviews(Guid itemId)
+        {
+            return Task.Run<IEnumerable<ItemReview>>(() =>
+            {
+                var path = Path.Combine(_criticReviewsPath, itemId + ".json");
+
+                try
+                {
+                    return _jsonSerializer.DeserializeFromFile<List<ItemReview>>(path);
+                }
+                catch (IOException)
+                {
+                    // File doesn't exist or is currently bring written to
+                    return new List<ItemReview>();
+                }
+            });
+        }
+
+        /// <summary>
+        /// Saves the critic reviews.
+        /// </summary>
+        /// <param name="itemId">The item id.</param>
+        /// <param name="criticReviews">The critic reviews.</param>
+        /// <returns>Task.</returns>
+        public Task SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
+        {
+            return Task.Run(() =>
+            {
+                if (!Directory.Exists(_criticReviewsPath))
+                {
+                    Directory.CreateDirectory(_criticReviewsPath);
+                }
+
+                var path = Path.Combine(_criticReviewsPath, itemId + ".json");
+
+                _jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
+            });
+        }
+
+        public void Dispose()
+        {
+            // Wait up to two seconds for any existing writes to finish
+            var locks = _fileLocks.Values.ToList()
+                                  .Where(i => i.CurrentCount == 1)
+                                  .Select(i => i.WaitAsync(2000));
+
+            var task = Task.WhenAll(locks);
+
+            Task.WaitAll(task);
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/JsonUserDataRepository.cs
similarity index 53%
rename from MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
rename to MediaBrowser.Server.Implementations/Persistence/JsonUserDataRepository.cs
index d378809ffb..2f1129bebc 100644
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/JsonUserDataRepository.cs
@@ -1,31 +1,28 @@
-using System.Data.SQLite;
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Concurrent;
-using System.Data;
 using System.IO;
+using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.Implementations.Sqlite
+namespace MediaBrowser.Server.Implementations.Persistence
 {
-    /// <summary>
-    /// Class SQLiteUserDataRepository
-    /// </summary>
-    public class SQLiteUserDataRepository : SqliteRepository, IUserDataRepository
+    public class JsonUserDataRepository : IUserDataRepository
     {
-        private readonly ConcurrentDictionary<string, Task<UserItemData>> _userData = new ConcurrentDictionary<string, Task<UserItemData>>();
+        private readonly ConcurrentDictionary<string, SemaphoreSlim> _fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
 
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
-        /// <summary>
-        /// The repository name
-        /// </summary>
-        public const string RepositoryName = "SQLite";
+        private SemaphoreSlim GetLock(string filename)
+        {
+            return _fileLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+        }
+        
+        private readonly ConcurrentDictionary<string, UserItemData> _userData = new ConcurrentDictionary<string, UserItemData>();
 
         /// <summary>
         /// Gets the name of the repository
@@ -35,19 +32,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         {
             get
             {
-                return RepositoryName;
+                return "Json";
             }
         }
 
         private readonly IJsonSerializer _jsonSerializer;
 
-        /// <summary>
-        /// The _app paths
-        /// </summary>
-        private readonly IApplicationPaths _appPaths;
+        private readonly string _dataPath;
+
+        private readonly ILogger _logger;
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
+        /// Initializes a new instance of the <see cref="JsonUserDataRepository" /> class.
         /// </summary>
         /// <param name="appPaths">The app paths.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
@@ -57,8 +53,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         /// or
         /// appPaths
         /// </exception>
-        public SQLiteUserDataRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
-            : base(logManager)
+        public JsonUserDataRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
         {
             if (jsonSerializer == null)
             {
@@ -69,30 +64,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite
                 throw new ArgumentNullException("appPaths");
             }
 
+            _logger = logManager.GetLogger(GetType().Name);
             _jsonSerializer = jsonSerializer;
-            _appPaths = appPaths;
+            _dataPath = Path.Combine(appPaths.DataPath, "userdata");
         }
 
         /// <summary>
         /// Opens the connection to the database
         /// </summary>
         /// <returns>Task.</returns>
-        public async Task Initialize()
+        public Task Initialize()
         {
-            var dbFile = Path.Combine(_appPaths.DataPath, "userdata.db");
-
-            await ConnectToDb(dbFile).ConfigureAwait(false);
-
-            string[] queries = {
-
-                                "create table if not exists userdata (key nvarchar, userId GUID, data BLOB)",
-                                "create unique index if not exists userdataindex on userdata (key, userId)",
-                                "create table if not exists schema_version (table_name primary key, version)",
-                                //pragmas
-                                "pragma temp_store = memory"
-                               };
-
-            RunQueries(queries);
+            return Task.FromResult(true);
         }
 
         /// <summary>
@@ -135,14 +118,12 @@ namespace MediaBrowser.Server.Implementations.Sqlite
             {
                 await PersistUserData(userId, key, userData, cancellationToken).ConfigureAwait(false);
 
-                var newValue = Task.FromResult(userData);
-
                 // Once it succeeds, put it into the dictionary to make it available to everyone else
-                _userData.AddOrUpdate(GetInternalKey(userId, key), newValue, delegate { return newValue; });
+                _userData.AddOrUpdate(GetInternalKey(userId, key), userData, delegate { return userData; });
             }
             catch (Exception ex)
             {
-                Logger.ErrorException("Error saving user data", ex);
+                _logger.ErrorException("Error saving user data", ex);
 
                 throw;
             }
@@ -171,60 +152,25 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         {
             cancellationToken.ThrowIfCancellationRequested();
 
-            var serialized = _jsonSerializer.SerializeToBytes(userData);
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            SQLiteTransaction transaction = null;
+            var path = GetUserDataPath(userId, key);
 
-            try
+            var parentPath = Path.GetDirectoryName(path);
+            if (!Directory.Exists(parentPath))
             {
-                transaction = Connection.BeginTransaction();
-
-                using (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);
-
-                    cmd.Transaction = transaction;
-
-                    await cmd.ExecuteNonQueryAsync(cancellationToken);
-                }
-
-                transaction.Commit();
+                Directory.CreateDirectory(parentPath);
             }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
 
-                throw;
-            }
-            catch (Exception e)
-            {
-                Logger.ErrorException("Failed to save user data:", e);
+            var semaphore = GetLock(path);
 
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
+            await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
-                throw;
+            try
+            {
+                _jsonSerializer.SerializeToFile(userData, path);
             }
             finally
             {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
+                semaphore.Release();
             }
         }
 
@@ -239,7 +185,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         /// or
         /// key
         /// </exception>
-        public Task<UserItemData> GetUserData(Guid userId, string key)
+        public UserItemData GetUserData(Guid userId, string key)
         {
             if (userId == Guid.Empty)
             {
@@ -259,31 +205,42 @@ namespace MediaBrowser.Server.Implementations.Sqlite
         /// <param name="userId">The user id.</param>
         /// <param name="key">The key.</param>
         /// <returns>Task{UserItemData}.</returns>
-        private async Task<UserItemData> RetrieveUserData(Guid userId, string key)
+        private UserItemData RetrieveUserData(Guid userId, string key)
         {
-            using (var cmd = Connection.CreateCommand())
+            var path = GetUserDataPath(userId, key);
+
+            try
+            {
+                return _jsonSerializer.DeserializeFromFile<UserItemData>(path);
+            }
+            catch (IOException)
             {
-                cmd.CommandText = "select data from userdata where key = @key and userId=@userId";
-
-                var idParam = cmd.Parameters.Add("@key", DbType.String);
-                idParam.Value = key;
-
-                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 stream = GetStream(reader, 0))
-                        {
-                            return _jsonSerializer.DeserializeFromStream<UserItemData>(stream);
-                        }
-                    }
-                }
-
-                return new UserItemData();
+                // File doesn't exist or is currently bring written to
+                return new UserItemData { UserId = userId };
             }
         }
+
+        private string GetUserDataPath(Guid userId, string key)
+        {
+            var userFolder = Path.Combine(_dataPath, userId.ToString());
+
+            var keyHash = key.GetMD5().ToString();
+
+            var prefix = keyHash.Substring(0, 1);
+
+            return Path.Combine(userFolder, prefix, keyHash + ".json");
+        }
+
+        public void Dispose()
+        {
+            // Wait up to two seconds for any existing writes to finish
+            var locks = _fileLocks.Values.ToList()
+                                  .Where(i => i.CurrentCount == 1)
+                                  .Select(i => i.WaitAsync(2000));
+
+            var task = Task.WhenAll(locks);
+
+            Task.WaitAll(task);
+        }
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Persistence/JsonUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/JsonUserRepository.cs
new file mode 100644
index 0000000000..0573c6e2ef
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Persistence/JsonUserRepository.cs
@@ -0,0 +1,189 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Persistence
+{
+    public class JsonUserRepository : IUserRepository
+    {
+        private readonly ConcurrentDictionary<string, SemaphoreSlim> _fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
+
+        private SemaphoreSlim GetLock(string filename)
+        {
+            return _fileLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+        }
+        
+        /// <summary>
+        /// Gets the name of the repository
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get
+            {
+                return "Json";
+            }
+        }
+
+        /// <summary>
+        /// Gets the json serializer.
+        /// </summary>
+        /// <value>The json serializer.</value>
+        private readonly IJsonSerializer _jsonSerializer;
+
+        private readonly string _dataPath;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="JsonUserRepository"/> class.
+        /// </summary>
+        /// <param name="appPaths">The app paths.</param>
+        /// <param name="jsonSerializer">The json serializer.</param>
+        /// <param name="logManager">The log manager.</param>
+        /// <exception cref="System.ArgumentNullException">
+        /// appPaths
+        /// or
+        /// jsonSerializer
+        /// </exception>
+        public JsonUserRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
+        {
+            if (appPaths == null)
+            {
+                throw new ArgumentNullException("appPaths");
+            }
+            if (jsonSerializer == null)
+            {
+                throw new ArgumentNullException("jsonSerializer");
+            }
+
+            _jsonSerializer = jsonSerializer;
+
+            _dataPath = Path.Combine(appPaths.DataPath, "users");
+        }
+
+        /// <summary>
+        /// Opens the connection to the database
+        /// </summary>
+        /// <returns>Task.</returns>
+        public Task Initialize()
+        {
+            return Task.FromResult(true);
+        }
+
+        /// <summary>
+        /// Save a user in the repo
+        /// </summary>
+        /// <param name="user">The user.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.ArgumentNullException">user</exception>
+        public async Task SaveUser(User user, CancellationToken cancellationToken)
+        {
+            if (user == null)
+            {
+                throw new ArgumentNullException("user");
+            }
+
+            if (cancellationToken == null)
+            {
+                throw new ArgumentNullException("cancellationToken");
+            }
+
+            cancellationToken.ThrowIfCancellationRequested();
+
+            if (!Directory.Exists(_dataPath))
+            {
+                Directory.CreateDirectory(_dataPath);
+            }
+
+            var path = Path.Combine(_dataPath, user.Id + ".json");
+
+            var semaphore = GetLock(path);
+
+            await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+            try
+            {
+                _jsonSerializer.SerializeToFile(user, path);
+            }
+            finally
+            {
+                semaphore.Release();
+            }
+        }
+
+        /// <summary>
+        /// Retrieve all users from the database
+        /// </summary>
+        /// <returns>IEnumerable{User}.</returns>
+        public IEnumerable<User> RetrieveAllUsers()
+        {
+            try
+            {
+                return Directory.EnumerateFiles(_dataPath, "*.json", SearchOption.TopDirectoryOnly)
+                    .Select(i => _jsonSerializer.DeserializeFromFile<User>(i));
+            }
+            catch (IOException)
+            {
+                return new List<User>();
+            }
+        }
+
+        /// <summary>
+        /// Deletes the user.
+        /// </summary>
+        /// <param name="user">The user.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        /// <exception cref="System.ArgumentNullException">user</exception>
+        public async Task DeleteUser(User user, CancellationToken cancellationToken)
+        {
+            if (user == null)
+            {
+                throw new ArgumentNullException("user");
+            }
+
+            if (cancellationToken == null)
+            {
+                throw new ArgumentNullException("cancellationToken");
+            }
+
+            cancellationToken.ThrowIfCancellationRequested();
+
+            var path = Path.Combine(_dataPath, user.Id + ".json");
+
+            var semaphore = GetLock(path);
+
+            await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+            try
+            {
+                File.Delete(path);
+            }
+            finally
+            {
+                semaphore.Release();
+            }
+        }
+
+        public void Dispose()
+        {
+            // Wait up to two seconds for any existing writes to finish
+            var locks = _fileLocks.Values.ToList()
+                                  .Where(i => i.CurrentCount == 1)
+                                  .Select(i => i.WaitAsync(2000));
+
+            var task = Task.WhenAll(locks);
+
+            Task.WaitAll(task);
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
index 08398e22e3..beab6200f2 100644
--- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
+++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
@@ -106,6 +106,11 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// <returns>Task{System.Boolean}.</returns>
         public async Task<bool> ExecuteMetadataProviders(BaseItem item, CancellationToken cancellationToken, bool force = false, bool allowSlowProviders = true)
         {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+
             // Allow providers of the same priority to execute in parallel
             MetadataProviderPriority? currentPriority = null;
             var currentTasks = new List<Task<bool>>();
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
index 12f98cef39..d63494c1e8 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/VideoImagesTask.cs
@@ -210,9 +210,9 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         {
             var allItems = sourceItems.ToList();
 
-            var localTrailers = allItems.SelectMany(i => _itemRepo.GetItems(i.LocalTrailerIds).Cast<Video>());
+            var localTrailers = allItems.SelectMany(i => _itemRepo.RetrieveItems<Trailer>(i.LocalTrailerIds));
 
-            var themeVideos = allItems.SelectMany(i => _itemRepo.GetItems(i.ThemeVideoIds).Cast<Video>());
+            var themeVideos = allItems.SelectMany(i => _itemRepo.RetrieveItems<Video>(i.ThemeVideoIds));
 
             var videos = allItems.OfType<Video>().ToList();
 
@@ -222,8 +222,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
 
             items.AddRange(themeVideos);
 
-            items.AddRange(videos.SelectMany(i => _itemRepo.GetItems(i.AdditionalPartIds).Cast<Video>()).ToList());
-            items.AddRange(videos.OfType<Movie>().SelectMany(i => _itemRepo.GetItems(i.SpecialFeatureIds).Cast<Video>()).ToList());
+            items.AddRange(videos.SelectMany(i => _itemRepo.RetrieveItems<Video>(i.AdditionalPartIds)).ToList());
+            items.AddRange(videos.OfType<Movie>().SelectMany(i => _itemRepo.RetrieveItems<Video>(i.SpecialFeatureIds)).ToList());
 
             return items.Where(i =>
             {
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index 29ce2698c3..dda9658d45 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -215,7 +215,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var key = item.GetUserDataKey();
 
-            var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
+            var data = _userDataRepository.GetUserData(user.Id, key);
 
             data.PlayCount++;
             data.LastPlayedDate = DateTime.UtcNow;
@@ -226,7 +226,7 @@ namespace MediaBrowser.Server.Implementations.Session
             }
 
             await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
-            
+
             // Nothing to save here
             // Fire events to inform plugins
             EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs
@@ -266,7 +266,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             if (positionTicks.HasValue)
             {
-                var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
+                var data = _userDataRepository.GetUserData(user.Id, key);
 
                 UpdatePlayState(item, data, positionTicks.Value);
                 await _userDataRepository.SaveUserData(user.Id, key, data, CancellationToken.None).ConfigureAwait(false);
@@ -307,7 +307,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var key = item.GetUserDataKey();
 
-            var data = await _userDataRepository.GetUserData(user.Id, key).ConfigureAwait(false);
+            var data = _userDataRepository.GetUserData(user.Id, key);
 
             if (positionTicks.HasValue)
             {
diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
index c634c760e4..2abd4d0f20 100644
--- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
         /// <returns>DateTime.</returns>
         private DateTime GetDate(BaseItem x)
         {
-            var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey()).Result;
+            var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey());
 
             if (userdata != null && userdata.LastPlayedDate.HasValue)
             {
diff --git a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
index a7cbd21499..d4c22e6e02 100644
--- a/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/PlayCountComparer.cs
@@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Sorting
         /// <returns>DateTime.</returns>
         private int GetValue(BaseItem x)
         {
-            var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey()).Result;
+            var userdata = UserDataRepository.GetUserData(User.Id, x.GetUserDataKey());
 
             return userdata == null ? 0 : userdata.PlayCount;
         }
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
deleted file mode 100644
index 60c3c1fe02..0000000000
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs
+++ /dev/null
@@ -1,209 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Data;
-using System.Data.SQLite;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Sqlite
-{
-    /// <summary>
-    /// Class SQLiteDisplayPreferencesRepository
-    /// </summary>
-    public class SQLiteDisplayPreferencesRepository : SqliteRepository, IDisplayPreferencesRepository
-    {
-        /// <summary>
-        /// The repository name
-        /// </summary>
-        public const string RepositoryName = "SQLite";
-
-        /// <summary>
-        /// Gets the name of the repository
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get
-            {
-                return RepositoryName;
-            }
-        }
-
-        /// <summary>
-        /// The _json serializer
-        /// </summary>
-        private readonly IJsonSerializer _jsonSerializer;
-
-        /// <summary>
-        /// The _app paths
-        /// </summary>
-        private readonly IApplicationPaths _appPaths;
-
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-        
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
-        /// </summary>
-        /// <param name="appPaths">The app paths.</param>
-        /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <exception cref="System.ArgumentNullException">
-        /// jsonSerializer
-        /// or
-        /// appPaths
-        /// </exception>
-        public SQLiteDisplayPreferencesRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
-            : base(logManager)
-        {
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentNullException("jsonSerializer");
-            }
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException("appPaths");
-            }
-
-            _jsonSerializer = jsonSerializer;
-            _appPaths = appPaths;
-        }
-
-        /// <summary>
-        /// Opens the connection to the database
-        /// </summary>
-        /// <returns>Task.</returns>
-        public async Task Initialize()
-        {
-            var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db");
-
-            await ConnectToDb(dbFile).ConfigureAwait(false);
-
-            string[] queries = {
-
-                                "create table if not exists displaypreferences (id GUID, data BLOB)",
-                                "create unique index if not exists displaypreferencesindex on displaypreferences (id)",
-                                "create table if not exists schema_version (table_name primary key, version)",
-                                //pragmas
-                                "pragma temp_store = memory"
-                               };
-
-            RunQueries(queries);
-        }
-
-        /// <summary>
-        /// Save the display preferences associated with an item in the repo
-        /// </summary>
-        /// <param name="displayPreferences">The display preferences.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException">item</exception>
-        public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, CancellationToken cancellationToken)
-        {
-            if (displayPreferences == null)
-            {
-                throw new ArgumentNullException("displayPreferences");
-            }
-            if (displayPreferences.Id == Guid.Empty)
-            {
-                throw new ArgumentNullException("displayPreferences.Id");
-            }
-            if (cancellationToken == null)
-            {
-                throw new ArgumentNullException("cancellationToken");
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            var serialized = _jsonSerializer.SerializeToBytes(displayPreferences);
-
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            SQLiteTransaction transaction = null;
-
-            try
-            {
-                transaction = Connection.BeginTransaction();
-
-                using (var cmd = Connection.CreateCommand())
-                {
-                    cmd.CommandText = "replace into displaypreferences (id, data) values (@1, @2)";
-                    cmd.AddParam("@1", displayPreferences.Id);
-                    cmd.AddParam("@2", serialized);
-
-                    cmd.Transaction = transaction;
-
-                    await cmd.ExecuteNonQueryAsync(cancellationToken);
-                }
-
-                transaction.Commit();
-            }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            catch (Exception e)
-            {
-                Logger.ErrorException("Failed to save display preferences:", e);
-
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            finally
-            {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
-            }
-        }
-
-        /// <summary>
-        /// Gets the display preferences.
-        /// </summary>
-        /// <param name="displayPreferencesId">The display preferences id.</param>
-        /// <returns>Task{DisplayPreferences}.</returns>
-        /// <exception cref="System.ArgumentNullException">item</exception>
-        public async Task<DisplayPreferences> GetDisplayPreferences(Guid displayPreferencesId)
-        {
-            if (displayPreferencesId == Guid.Empty)
-            {
-                throw new ArgumentNullException("displayPreferencesId");
-            }
-
-            var cmd = Connection.CreateCommand();
-            cmd.CommandText = "select data from displaypreferences where id = @id";
-
-            var idParam = cmd.Parameters.Add("@id", DbType.Guid);
-            idParam.Value = displayPreferencesId;
-
-            using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow).ConfigureAwait(false))
-            {
-                if (reader.Read())
-                {
-                    using (var stream = GetStream(reader, 0))
-                    {
-                        return _jsonSerializer.DeserializeFromStream<DisplayPreferences>(stream);
-                    }
-                }
-            }
-
-            return null;
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs
deleted file mode 100644
index 6aed8a3528..0000000000
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteExtensions.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Data;
-using System.Data.SQLite;
-
-namespace MediaBrowser.Server.Implementations.Sqlite
-{
-    /// <summary>
-    /// Class SQLiteExtensions
-    /// </summary>
-    static class SQLiteExtensions
-    {
-        /// <summary>
-        /// Adds the param.
-        /// </summary>
-        /// <param name="cmd">The CMD.</param>
-        /// <param name="param">The param.</param>
-        /// <returns>SQLiteParameter.</returns>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public static SQLiteParameter AddParam(this SQLiteCommand cmd, string param)
-        {
-            if (string.IsNullOrEmpty(param))
-            {
-                throw new ArgumentNullException();
-            }
-            
-            var sqliteParam = new SQLiteParameter(param);
-            cmd.Parameters.Add(sqliteParam);
-            return sqliteParam;
-        }
-
-        /// <summary>
-        /// Adds the param.
-        /// </summary>
-        /// <param name="cmd">The CMD.</param>
-        /// <param name="param">The param.</param>
-        /// <param name="data">The data.</param>
-        /// <returns>SQLiteParameter.</returns>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public static SQLiteParameter AddParam(this SQLiteCommand cmd, string param, object data)
-        {
-            if (string.IsNullOrEmpty(param))
-            {
-                throw new ArgumentNullException();
-            }
-
-            var sqliteParam = AddParam(cmd, param);
-            sqliteParam.Value = data;
-            return sqliteParam;
-        }
-
-        /// <summary>
-        /// Determines whether the specified conn is open.
-        /// </summary>
-        /// <param name="conn">The conn.</param>
-        /// <returns><c>true</c> if the specified conn is open; otherwise, <c>false</c>.</returns>
-        public static bool IsOpen(this SQLiteConnection conn)
-        {
-            return conn.State == ConnectionState.Open;
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
deleted file mode 100644
index a068b7cccc..0000000000
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteItemRepository.cs
+++ /dev/null
@@ -1,524 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Server.Implementations.Reflection;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Data.SQLite;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Sqlite
-{
-    /// <summary>
-    /// Class SQLiteItemRepository
-    /// </summary>
-    public class SQLiteItemRepository : SqliteRepository, IItemRepository
-    {
-        /// <summary>
-        /// The _type mapper
-        /// </summary>
-        private readonly TypeMapper _typeMapper = new TypeMapper();
-
-        /// <summary>
-        /// The repository name
-        /// </summary>
-        public const string RepositoryName = "SQLite";
-
-        /// <summary>
-        /// Gets the name of the repository
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get
-            {
-                return RepositoryName;
-            }
-        }
-
-        /// <summary>
-        /// Gets the json serializer.
-        /// </summary>
-        /// <value>The json serializer.</value>
-        private readonly IJsonSerializer _jsonSerializer;
-
-        /// <summary>
-        /// The _app paths
-        /// </summary>
-        private readonly IApplicationPaths _appPaths;
-
-        /// <summary>
-        /// The _save item command
-        /// </summary>
-        private SQLiteCommand _saveItemCommand;
-        /// <summary>
-        /// The _delete children command
-        /// </summary>
-        private SQLiteCommand _deleteChildrenCommand;
-        /// <summary>
-        /// The _save children command
-        /// </summary>
-        private SQLiteCommand _saveChildrenCommand;
-
-        private string _criticReviewsPath;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
-        /// </summary>
-        /// <param name="appPaths">The app paths.</param>
-        /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <exception cref="System.ArgumentNullException">appPaths</exception>
-        public SQLiteItemRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
-            : base(logManager)
-        {
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException("appPaths");
-            }
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentNullException("jsonSerializer");
-            }
-
-            _appPaths = appPaths;
-            _jsonSerializer = jsonSerializer;
-
-            _criticReviewsPath = Path.Combine(_appPaths.DataPath, "critic-reviews");
-        }
-
-        /// <summary>
-        /// Opens the connection to the database
-        /// </summary>
-        /// <returns>Task.</returns>
-        public async Task Initialize()
-        {
-            var dbFile = Path.Combine(_appPaths.DataPath, "library.db");
-
-            await ConnectToDb(dbFile).ConfigureAwait(false);
-
-            string[] queries = {
-
-                                "create table if not exists items (guid GUID primary key, obj_type, data BLOB)",
-                                "create index if not exists idx_items on items(guid)",
-                                "create table if not exists children (guid GUID, child GUID)", 
-                                "create unique index if not exists idx_children on children(guid, child)",
-                                "create table if not exists schema_version (table_name primary key, version)",
-                                //triggers
-                                TriggerSql,
-                                //pragmas
-                                "pragma temp_store = memory"
-                               };
-
-            RunQueries(queries);
-
-            PrepareStatements();
-        }
-
-        //cascade delete triggers
-        /// <summary>
-        /// The trigger SQL
-        /// </summary>
-        protected string TriggerSql =
-            @"CREATE TRIGGER if not exists delete_item
-                AFTER DELETE
-                ON items
-                FOR EACH ROW
-                BEGIN
-                    DELETE FROM children WHERE children.guid = old.child;
-                    DELETE FROM children WHERE children.child = old.child;
-                END";
-
-        /// <summary>
-        /// The _write lock
-        /// </summary>
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-
-        /// <summary>
-        /// Prepares the statements.
-        /// </summary>
-        private void PrepareStatements()
-        {
-            _saveItemCommand = new SQLiteCommand
-            {
-                CommandText = "replace into items (guid, obj_type, data) values (@1, @2, @3)"
-            };
-
-            _saveItemCommand.Parameters.Add(new SQLiteParameter("@1"));
-            _saveItemCommand.Parameters.Add(new SQLiteParameter("@2"));
-            _saveItemCommand.Parameters.Add(new SQLiteParameter("@3"));
-
-            _deleteChildrenCommand = new SQLiteCommand
-            {
-                CommandText = "delete from children where guid = @guid"
-            };
-            _deleteChildrenCommand.Parameters.Add(new SQLiteParameter("@guid"));
-
-            _saveChildrenCommand = new SQLiteCommand
-            {
-                CommandText = "replace into children (guid, child) values (@guid, @child)"
-            };
-            _saveChildrenCommand.Parameters.Add(new SQLiteParameter("@guid"));
-            _saveChildrenCommand.Parameters.Add(new SQLiteParameter("@child"));
-        }
-
-        /// <summary>
-        /// Save a standard item in the repo
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException">item</exception>
-        public Task SaveItem(BaseItem item, CancellationToken cancellationToken)
-        {
-            if (item == null)
-            {
-                throw new ArgumentNullException("item");
-            }
-
-            return SaveItems(new[] { item }, cancellationToken);
-        }
-
-        /// <summary>
-        /// Saves the items.
-        /// </summary>
-        /// <param name="items">The items.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException">
-        /// items
-        /// or
-        /// cancellationToken
-        /// </exception>
-        public async Task SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
-        {
-            if (items == null)
-            {
-                throw new ArgumentNullException("items");
-            }
-
-            if (cancellationToken == null)
-            {
-                throw new ArgumentNullException("cancellationToken");
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            SQLiteTransaction transaction = null;
-
-            try
-            {
-                transaction = Connection.BeginTransaction();
-
-                foreach (var item in items)
-                {
-                    cancellationToken.ThrowIfCancellationRequested();
-                    
-                    _saveItemCommand.Parameters[0].Value = item.Id;
-                    _saveItemCommand.Parameters[1].Value = item.GetType().FullName;
-                    _saveItemCommand.Parameters[2].Value = _jsonSerializer.SerializeToBytes(item);
-
-                    _saveItemCommand.Transaction = transaction;
-
-                    await _saveItemCommand.ExecuteNonQueryAsync(cancellationToken);
-                }
-                
-                transaction.Commit();
-            }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            catch (Exception e)
-            {
-                Logger.ErrorException("Failed to save items:", e);
-
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            finally
-            {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
-            }
-        }
-
-        /// <summary>
-        /// Retrieve a standard item from the repo
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <returns>BaseItem.</returns>
-        /// <exception cref="System.ArgumentNullException">id</exception>
-        /// <exception cref="System.ArgumentException"></exception>
-        public BaseItem GetItem(Guid id)
-        {
-            if (id == Guid.Empty)
-            {
-                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>
-        /// <param name="id">The id.</param>
-        /// <returns>BaseItem.</returns>
-        /// <exception cref="System.ArgumentNullException">id</exception>
-        /// <exception cref="System.ArgumentException"></exception>
-        protected BaseItem RetrieveItemInternal(Guid id)
-        {
-            if (id == Guid.Empty)
-            {
-                throw new ArgumentNullException("id");
-            }
-
-            using (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))
-                {
-                    if (reader.Read())
-                    {
-                        var type = reader.GetString(0);
-                        using (var stream = GetStream(reader, 1))
-                        {
-                            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);
-                                return null;
-                            }
-
-                            var item = _jsonSerializer.DeserializeFromStream(stream, itemType);
-                            return item as BaseItem;
-                        }
-                    }
-                }
-                return null;
-            }
-        }
-
-        /// <summary>
-        /// Retrieve all the children of the given folder
-        /// </summary>
-        /// <param name="parent">The parent.</param>
-        /// <returns>IEnumerable{BaseItem}.</returns>
-        /// <exception cref="System.ArgumentNullException"></exception>
-        public IEnumerable<BaseItem> RetrieveChildren(Folder parent)
-        {
-            if (parent == null)
-            {
-                throw new ArgumentNullException();
-            }
-
-            using (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))
-                {
-                    while (reader.Read())
-                    {
-                        var type = reader.GetString(0);
-
-                        using (var stream = GetStream(reader, 1))
-                        {
-                            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;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Save references to all the children for the given folder
-        /// (Doesn't actually save the child entities)
-        /// </summary>
-        /// <param name="id">The id.</param>
-        /// <param name="children">The children.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException">id</exception>
-        public async Task SaveChildren(Guid id, IEnumerable<BaseItem> children, CancellationToken cancellationToken)
-        {
-            if (id == Guid.Empty)
-            {
-                throw new ArgumentNullException("id");
-            }
-
-            if (children == null)
-            {
-                throw new ArgumentNullException("children");
-            }
-
-            if (cancellationToken == null)
-            {
-                throw new ArgumentNullException("cancellationToken");
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            SQLiteTransaction transaction = null;
-
-            try
-            {
-                transaction = Connection.BeginTransaction();
-
-                // Delete exising children
-                _deleteChildrenCommand.Parameters[0].Value = id;
-                _deleteChildrenCommand.Transaction = transaction;
-                await _deleteChildrenCommand.ExecuteNonQueryAsync(cancellationToken);
-
-                // Save new children
-                foreach (var child in children)
-                {
-                    _saveChildrenCommand.Transaction = transaction;
-
-                    _saveChildrenCommand.Parameters[0].Value = id;
-                    _saveChildrenCommand.Parameters[1].Value = child.Id;
-
-                    await _saveChildrenCommand.ExecuteNonQueryAsync(cancellationToken);
-                }
-
-                transaction.Commit();
-            }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            catch (Exception e)
-            {
-                Logger.ErrorException("Failed to save children:", e);
-
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            finally
-            {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
-            }
-        }
-
-        /// <summary>
-        /// Gets the critic reviews.
-        /// </summary>
-        /// <param name="itemId">The item id.</param>
-        /// <returns>Task{IEnumerable{ItemReview}}.</returns>
-        public Task<IEnumerable<ItemReview>> GetCriticReviews(Guid itemId)
-        {
-            return Task.Run<IEnumerable<ItemReview>>(() =>
-            {
-
-                try
-                {
-                    var path = Path.Combine(_criticReviewsPath, itemId + ".json");
-
-                    return _jsonSerializer.DeserializeFromFile<List<ItemReview>>(path);
-                }
-                catch (DirectoryNotFoundException)
-                {
-                    return new List<ItemReview>();
-                }
-                catch (FileNotFoundException)
-                {
-                    return new List<ItemReview>();
-                }
-
-            });
-        }
-
-        /// <summary>
-        /// Saves the critic reviews.
-        /// </summary>
-        /// <param name="itemId">The item id.</param>
-        /// <param name="criticReviews">The critic reviews.</param>
-        /// <returns>Task.</returns>
-        public Task SaveCriticReviews(Guid itemId, IEnumerable<ItemReview> criticReviews)
-        {
-            return Task.Run(() =>
-            {
-                if (!Directory.Exists(_criticReviewsPath))
-                {
-                    Directory.CreateDirectory(_criticReviewsPath);
-                }
-
-                var path = Path.Combine(_criticReviewsPath, itemId + ".json");
-
-                _jsonSerializer.SerializeToFile(criticReviews.ToList(), path);
-            });
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
deleted file mode 100644
index 6cd816e51c..0000000000
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.Data;
-using System.Data.Common;
-using System.Data.SQLite;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Sqlite
-{
-    /// <summary>
-    /// Class SqliteRepository
-    /// </summary>
-    public abstract class SqliteRepository : IDisposable
-    {
-        /// <summary>
-        /// The db file name
-        /// </summary>
-        protected string DbFileName;
-        /// <summary>
-        /// The connection
-        /// </summary>
-        protected SQLiteConnection Connection;
-
-        /// <summary>
-        /// Gets the logger.
-        /// </summary>
-        /// <value>The logger.</value>
-        protected ILogger Logger { get; private set; }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SqliteRepository" /> class.
-        /// </summary>
-        /// <param name="logManager">The log manager.</param>
-        /// <exception cref="System.ArgumentNullException">logger</exception>
-        protected SqliteRepository(ILogManager logManager)
-        {
-            if (logManager == null)
-            {
-                throw new ArgumentNullException("logManager");
-            }
-
-            Logger = logManager.GetLogger(GetType().Name);
-        }
-
-        /// <summary>
-        /// Connects to DB.
-        /// </summary>
-        /// <param name="dbPath">The db path.</param>
-        /// <returns>Task{System.Boolean}.</returns>
-        /// <exception cref="System.ArgumentNullException">dbPath</exception>
-        protected Task ConnectToDb(string dbPath)
-        {
-            if (string.IsNullOrEmpty(dbPath))
-            {
-                throw new ArgumentNullException("dbPath");
-            }
-
-            DbFileName = dbPath;
-            var connectionstr = new SQLiteConnectionStringBuilder
-            {
-                PageSize = 4096,
-                CacheSize = 40960,
-                SyncMode = SynchronizationModes.Off,
-                DataSource = dbPath,
-                JournalMode = SQLiteJournalModeEnum.Wal
-            };
-
-            Connection = new SQLiteConnection(connectionstr.ConnectionString);
-
-            return Connection.OpenAsync();
-        }
-
-        /// <summary>
-        /// Runs the queries.
-        /// </summary>
-        /// <param name="queries">The queries.</param>
-        /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
-        /// <exception cref="System.ArgumentNullException">queries</exception>
-        protected void RunQueries(string[] queries)
-        {
-            if (queries == null)
-            {
-                throw new ArgumentNullException("queries");
-            }
-
-            using (var tran = Connection.BeginTransaction())
-            {
-                try
-                {
-                    using (var cmd = Connection.CreateCommand())
-                    {
-                        foreach (var query in queries)
-                        {
-                            cmd.Transaction = tran;
-                            cmd.CommandText = query;
-                            cmd.ExecuteNonQuery();
-                        }
-                    }
-
-                    tran.Commit();
-                }
-                catch (Exception e)
-                {
-                    Logger.ErrorException("Error running queries", e);
-                    tran.Rollback();
-                    throw;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-        /// </summary>
-        public void Dispose()
-        {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        private readonly object _disposeLock = new object();
-
-        /// <summary>
-        /// Releases unmanaged and - optionally - managed resources.
-        /// </summary>
-        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
-        protected virtual void Dispose(bool dispose)
-        {
-            if (dispose)
-            {
-                try
-                {
-                    lock (_disposeLock)
-                    {
-                        if (Connection != null)
-                        {
-                            if (Connection.IsOpen())
-                            {
-                                Connection.Close();
-                            }
-
-                            Connection.Dispose();
-                            Connection = null;
-                        }
-                    }
-                }
-                catch (Exception ex)
-                {
-                    Logger.ErrorException("Error disposing database", ex);
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets a stream from a DataReader at a given ordinal
-        /// </summary>
-        /// <param name="reader">The reader.</param>
-        /// <param name="ordinal">The ordinal.</param>
-        /// <returns>Stream.</returns>
-        /// <exception cref="System.ArgumentNullException">reader</exception>
-        protected static Stream GetStream(IDataReader reader, int ordinal)
-        {
-            if (reader == null)
-            {
-                throw new ArgumentNullException("reader");
-            }
-
-            var memoryStream = new MemoryStream();
-            var num = 0L;
-            var array = new byte[4096];
-            long bytes;
-            do
-            {
-                bytes = reader.GetBytes(ordinal, num, array, 0, array.Length);
-                memoryStream.Write(array, 0, (int)bytes);
-                num += bytes;
-            }
-            while (bytes > 0L);
-            memoryStream.Position = 0;
-            return memoryStream;
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
deleted file mode 100644
index 335841549a..0000000000
--- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs
+++ /dev/null
@@ -1,271 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Data.SQLite;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Sqlite
-{
-    /// <summary>
-    /// Class SQLiteUserRepository
-    /// </summary>
-    public class SQLiteUserRepository : SqliteRepository, IUserRepository
-    {
-        /// <summary>
-        /// The repository name
-        /// </summary>
-        public const string RepositoryName = "SQLite";
-
-        private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
-        
-        /// <summary>
-        /// Gets the name of the repository
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get
-            {
-                return RepositoryName;
-            }
-        }
-
-        /// <summary>
-        /// Gets the json serializer.
-        /// </summary>
-        /// <value>The json serializer.</value>
-        private readonly IJsonSerializer _jsonSerializer;
-
-        /// <summary>
-        /// The _app paths
-        /// </summary>
-        private readonly IApplicationPaths _appPaths;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class.
-        /// </summary>
-        /// <param name="appPaths">The app paths.</param>
-        /// <param name="jsonSerializer">The json serializer.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <exception cref="System.ArgumentNullException">appPaths</exception>
-        public SQLiteUserRepository(IApplicationPaths appPaths, IJsonSerializer jsonSerializer, ILogManager logManager)
-            : base(logManager)
-        {
-            if (appPaths == null)
-            {
-                throw new ArgumentNullException("appPaths");
-            }
-            if (jsonSerializer == null)
-            {
-                throw new ArgumentNullException("jsonSerializer");
-            }
-
-            _appPaths = appPaths;
-            _jsonSerializer = jsonSerializer;
-        }
-
-        /// <summary>
-        /// Opens the connection to the database
-        /// </summary>
-        /// <returns>Task.</returns>
-        public async Task Initialize()
-        {
-            var dbFile = Path.Combine(_appPaths.DataPath, "users.db");
-
-            await ConnectToDb(dbFile).ConfigureAwait(false);
-
-            string[] queries = {
-
-                                "create table if not exists users (guid GUID primary key, data BLOB)",
-                                "create index if not exists idx_users on users(guid)",
-                                "create table if not exists schema_version (table_name primary key, version)",
-                                //pragmas
-                                "pragma temp_store = memory"
-                               };
-
-            RunQueries(queries);
-        }
-
-        /// <summary>
-        /// Save a user in the repo
-        /// </summary>
-        /// <param name="user">The user.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException">user</exception>
-        public async Task SaveUser(User user, CancellationToken cancellationToken)
-        {
-            if (user == null)
-            {
-                throw new ArgumentNullException("user");
-            }
-
-            if (cancellationToken == null)
-            {
-                throw new ArgumentNullException("cancellationToken");
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            var serialized = _jsonSerializer.SerializeToBytes(user);
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            SQLiteTransaction transaction = null;
-
-            try
-            {
-                transaction = Connection.BeginTransaction();
-
-                using (var cmd = Connection.CreateCommand())
-                {
-                    cmd.CommandText = "replace into users (guid, data) values (@1, @2)";
-                    cmd.AddParam("@1", user.Id);
-                    cmd.AddParam("@2", serialized);
-
-                    cmd.Transaction = transaction;
-
-                    await cmd.ExecuteNonQueryAsync(cancellationToken);
-                }
-
-                transaction.Commit();
-            }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            catch (Exception e)
-            {
-                Logger.ErrorException("Failed to save user:", e);
-
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            finally
-            {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
-            }
-        }
-
-        /// <summary>
-        /// Retrieve all users from the database
-        /// </summary>
-        /// <returns>IEnumerable{User}.</returns>
-        public IEnumerable<User> RetrieveAllUsers()
-        {
-            using (var cmd = Connection.CreateCommand())
-            {
-                cmd.CommandText = "select data from users";
-
-                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
-                {
-                    while (reader.Read())
-                    {
-                        using (var stream = GetStream(reader, 0))
-                        {
-                            var user = _jsonSerializer.DeserializeFromStream<User>(stream);
-                            yield return user;
-                        }
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Deletes the user.
-        /// </summary>
-        /// <param name="user">The user.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentNullException">user</exception>
-        public async Task DeleteUser(User user, CancellationToken cancellationToken)
-        {
-            if (user == null)
-            {
-                throw new ArgumentNullException("user");
-            }
-
-            if (cancellationToken == null)
-            {
-                throw new ArgumentNullException("cancellationToken");
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
-
-            await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            SQLiteTransaction transaction = null;
-
-            try
-            {
-                transaction = Connection.BeginTransaction();
-
-                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;
-
-                    cmd.Transaction = transaction;
-
-                    await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
-                }
-
-                transaction.Commit();
-            }
-            catch (OperationCanceledException)
-            {
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            catch (Exception e)
-            {
-                Logger.ErrorException("Failed to delete user:", e);
-
-                if (transaction != null)
-                {
-                    transaction.Rollback();
-                }
-
-                throw;
-            }
-            finally
-            {
-                if (transaction != null)
-                {
-                    transaction.Dispose();
-                }
-
-                _writeLock.Release();
-            }
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 12b6ef6500..f13933eb6e 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -14,5 +14,4 @@
   <package id="ServiceStack.Redis" version="3.9.43" targetFramework="net45" />
   <package id="ServiceStack.Text" version="3.9.45" targetFramework="net45" />
   <package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
-  <package id="System.Data.SQLite.x86" version="1.0.86.0" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/App.config b/MediaBrowser.ServerApplication/App.config
index e461d8c9ea..a5cbacb614 100644
--- a/MediaBrowser.ServerApplication/App.config
+++ b/MediaBrowser.ServerApplication/App.config
@@ -33,10 +33,6 @@
         <assemblyIdentity name="System.Reactive.Interfaces" publicKeyToken="f300afd708cefcd3" culture="neutral" />
         <bindingRedirect oldVersion="0.0.0.0-2.0.20823.0" newVersion="2.0.20823.0" />
       </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Data.SQLite" publicKeyToken="db937bc2d44ff139" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-1.0.86.0" newVersion="1.0.86.0" />
-      </dependentAssembly>
       <dependentAssembly>
         <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
         <bindingRedirect oldVersion="0.0.0.0-1.5.11.0" newVersion="1.5.11.0" />
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 583053fa4e..da871cc120 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -38,10 +38,10 @@ using MediaBrowser.Server.Implementations.IO;
 using MediaBrowser.Server.Implementations.Library;
 using MediaBrowser.Server.Implementations.Localization;
 using MediaBrowser.Server.Implementations.MediaEncoder;
+using MediaBrowser.Server.Implementations.Persistence;
 using MediaBrowser.Server.Implementations.Providers;
 using MediaBrowser.Server.Implementations.ServerManager;
 using MediaBrowser.Server.Implementations.Session;
-using MediaBrowser.Server.Implementations.Sqlite;
 using MediaBrowser.Server.Implementations.Updates;
 using MediaBrowser.Server.Implementations.WebSocket;
 using MediaBrowser.ServerApplication.Implementations;
@@ -244,16 +244,16 @@ namespace MediaBrowser.ServerApplication
             ZipClient = new DotNetZipClient();
             RegisterSingleInstance(ZipClient);
 
-            UserDataRepository = new SQLiteUserDataRepository(ApplicationPaths, JsonSerializer, LogManager);
+            UserDataRepository = new JsonUserDataRepository(ApplicationPaths, JsonSerializer, LogManager);
             RegisterSingleInstance(UserDataRepository);
 
-            UserRepository = new SQLiteUserRepository(ApplicationPaths, JsonSerializer, LogManager);
+            UserRepository = new JsonUserRepository(ApplicationPaths, JsonSerializer, LogManager);
             RegisterSingleInstance(UserRepository);
 
-            DisplayPreferencesRepository = new SQLiteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
+            DisplayPreferencesRepository = new JsonDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager);
             RegisterSingleInstance(DisplayPreferencesRepository);
 
-            ItemRepository = new SQLiteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
+            ItemRepository = new JsonItemRepository(ApplicationPaths, JsonSerializer, LogManager);
             RegisterSingleInstance(ItemRepository);
 
             UserManager = new UserManager(Logger, ServerConfigurationManager);
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index aaa4ce6f8d..50221ef1c4 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.124</version>
+        <version>3.0.125</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.124" />
+            <dependency id="MediaBrowser.Common" version="3.0.125" />
             <dependency id="NLog" version="2.0.1.2" />
             <dependency id="ServiceStack.Text" version="3.9.45" />
             <dependency id="SimpleInjector" version="2.2.3" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 3e8859441d..225d65bd65 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.124</version>
+        <version>3.0.125</version>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index 6540d99cd2..1da7b5dcea 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.124</version>
+        <version>3.0.125</version>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.124" />
+            <dependency id="MediaBrowser.Common" version="3.0.125" />
         </dependencies>
     </metadata>
     <files>