diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs
index ef415ec57c..281f764b5f 100644
--- a/MediaBrowser.Api/ApiEntryPoint.cs
+++ b/MediaBrowser.Api/ApiEntryPoint.cs
@@ -132,6 +132,7 @@ namespace MediaBrowser.Api
         /// Called when [transcode beginning].
         /// </summary>
         /// <param name="path">The path.</param>
+        /// <param name="streamId">The stream identifier.</param>
         /// <param name="transcodingJobId">The transcoding job identifier.</param>
         /// <param name="type">The type.</param>
         /// <param name="process">The process.</param>
@@ -140,6 +141,7 @@ namespace MediaBrowser.Api
         /// <param name="cancellationTokenSource">The cancellation token source.</param>
         /// <returns>TranscodingJob.</returns>
         public TranscodingJob OnTranscodeBeginning(string path,
+            string streamId,
             string transcodingJobId,
             TranscodingJobType type,
             Process process,
@@ -157,7 +159,8 @@ namespace MediaBrowser.Api
                     ActiveRequestCount = 1,
                     DeviceId = deviceId,
                     CancellationTokenSource = cancellationTokenSource,
-                    Id = transcodingJobId
+                    Id = transcodingJobId,
+                    StreamId = streamId
                 };
 
                 _activeTranscodingJobs.Add(job);
@@ -316,17 +319,26 @@ namespace MediaBrowser.Api
         /// Kills the single transcoding job.
         /// </summary>
         /// <param name="deviceId">The device id.</param>
+        /// <param name="streamId">The stream identifier.</param>
         /// <param name="deleteFiles">The delete files.</param>
         /// <returns>Task.</returns>
-        /// <exception cref="ArgumentNullException">deviceId</exception>
-        internal void KillTranscodingJobs(string deviceId, Func<string, bool> deleteFiles)
+        internal void KillTranscodingJobs(string deviceId, string streamId, Func<string, bool> deleteFiles)
         {
             if (string.IsNullOrEmpty(deviceId))
             {
                 throw new ArgumentNullException("deviceId");
             }
 
-            KillTranscodingJobs(j => string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase), deleteFiles);
+            KillTranscodingJobs(j =>
+            {
+                if (string.Equals(deviceId, j.DeviceId, StringComparison.OrdinalIgnoreCase))
+                {
+                    return string.IsNullOrWhiteSpace(streamId) || string.Equals(streamId, j.StreamId, StringComparison.OrdinalIgnoreCase);
+                }
+
+                return false;
+
+            }, deleteFiles);
         }
 
         /// <summary>
@@ -335,7 +347,7 @@ namespace MediaBrowser.Api
         /// <param name="killJob">The kill job.</param>
         /// <param name="deleteFiles">The delete files.</param>
         /// <returns>Task.</returns>
-        internal void KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
+        private void KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles)
         {
             var jobs = new List<TranscodingJob>();
 
@@ -516,6 +528,11 @@ namespace MediaBrowser.Api
     /// </summary>
     public class TranscodingJob
     {
+        /// <summary>
+        /// Gets or sets the stream identifier.
+        /// </summary>
+        /// <value>The stream identifier.</value>
+        public string StreamId { get; set; }
         /// <summary>
         /// Gets or sets the path.
         /// </summary>
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index dff433c9dc..4465be97a2 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Dto;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
@@ -72,6 +73,29 @@ namespace MediaBrowser.Api
             return ResultFactory.GetOptimizedResultUsingCache(Request, cacheKey, lastDateModified, cacheDuration, factoryFn);
         }
 
+        protected void AssertCanUpdateUser(IUserManager userManager, string userId)
+        {
+            var auth = AuthorizationContext.GetAuthorizationInfo(Request);
+
+            var authenticatedUser = userManager.GetUserById(auth.UserId);
+
+            // If they're going to update the record of another user, they must be an administrator
+            if (!string.Equals(userId, auth.UserId, StringComparison.OrdinalIgnoreCase))
+            {
+                if (!authenticatedUser.Policy.IsAdministrator)
+                {
+                    throw new SecurityException("Unauthorized access.");
+                }
+            }
+            else
+            {
+                if (!authenticatedUser.Policy.EnableUserPreferenceAccess)
+                {
+                    throw new SecurityException("Unauthorized access.");
+                }
+            }
+        }
+        
         /// <summary>
         /// To the optimized serialized result using cache.
         /// </summary>
@@ -88,9 +112,9 @@ namespace MediaBrowser.Api
         /// Gets the session.
         /// </summary>
         /// <returns>SessionInfo.</returns>
-        protected SessionInfo GetSession()
+        protected async Task<SessionInfo> GetSession()
         {
-            var session = SessionContext.GetSession(Request);
+            var session = await SessionContext.GetSession(Request).ConfigureAwait(false);
 
             if (session == null)
             {
diff --git a/MediaBrowser.Api/ConnectService.cs b/MediaBrowser.Api/ConnectService.cs
index 4bcd33d9e3..bdd2eeaadd 100644
--- a/MediaBrowser.Api/ConnectService.cs
+++ b/MediaBrowser.Api/ConnectService.cs
@@ -1,8 +1,10 @@
-using MediaBrowser.Common.Extensions;
+using System;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Connect;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Connect;
+using MediaBrowser.Model.Dto;
 using ServiceStack;
 using System.Collections.Generic;
 using System.Linq;
@@ -73,6 +75,28 @@ namespace MediaBrowser.Api
         public string ConnectUserId { get; set; }
     }
 
+    [Route("/Connect/Supporters", "GET")]
+    [Authenticated(Roles = "Admin")]
+    public class GetConnectSupporterSummary : IReturn<ConnectSupporterSummary>
+    {
+    }
+
+    [Route("/Connect/Supporters", "DELETE")]
+    [Authenticated(Roles = "Admin")]
+    public class RemoveConnectSupporter : IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
+        public string Id { get; set; }
+    }
+
+    [Route("/Connect/Supporters", "POST")]
+    [Authenticated(Roles = "Admin")]
+    public class AddConnectSupporter : IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
+        public string Id { get; set; }
+    }
+
     public class ConnectService : BaseApiService
     {
         private readonly IConnectManager _connectManager;
@@ -84,6 +108,35 @@ namespace MediaBrowser.Api
             _userManager = userManager;
         }
 
+        public async Task<object> Get(GetConnectSupporterSummary request)
+        {
+            var result = await _connectManager.GetConnectSupporterSummary().ConfigureAwait(false);
+            var existingConnectUserIds = result.Users.Select(i => i.Id).ToList();
+
+            result.EligibleUsers = _userManager.Users
+                .Where(i => !string.IsNullOrWhiteSpace(i.ConnectUserId))
+                .Where(i => !existingConnectUserIds.Contains(i.ConnectUserId, StringComparer.OrdinalIgnoreCase))
+                .OrderBy(i => i.Name)
+                .Select(i => _userManager.GetUserDto(i))
+                .ToList();
+
+            return ToOptimizedResult(result);
+        }
+
+        public void Delete(RemoveConnectSupporter request)
+        {
+            var task = _connectManager.RemoveConnectSupporter(request.Id);
+
+            Task.WaitAll(task);
+        }
+
+        public void Post(AddConnectSupporter request)
+        {
+            var task = _connectManager.AddConnectSupporter(request.Id);
+
+            Task.WaitAll(task);
+        }
+
         public object Post(CreateConnectLink request)
         {
             return _connectManager.LinkUser(request.Id, request.ConnectUsername);
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index e29bbf6743..ec9b2571e1 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.Api.Images
     /// Class UpdateItemImageIndex
     /// </summary>
     [Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST", Summary = "Updates the index for an item image")]
-    [Authenticated]
+    [Authenticated(Roles = "admin")]
     public class UpdateItemImageIndex : IReturnVoid
     {
         /// <summary>
@@ -64,7 +64,7 @@ namespace MediaBrowser.Api.Images
         /// </summary>
         /// <value>The id.</value>
         [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public Guid Id { get; set; }
+        public string Id { get; set; }
 
         /// <summary>
         /// Gets or sets the type of the image.
@@ -143,7 +143,7 @@ namespace MediaBrowser.Api.Images
         /// </summary>
         /// <value>The id.</value>
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public Guid Id { get; set; }
+        public string Id { get; set; }
     }
 
     /// <summary>
@@ -151,7 +151,7 @@ namespace MediaBrowser.Api.Images
     /// </summary>
     [Route("/Items/{Id}/Images/{Type}", "DELETE")]
     [Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")]
-    [Authenticated]
+    [Authenticated(Roles = "admin")]
     public class DeleteItemImage : DeleteImageRequest, IReturnVoid
     {
         /// <summary>
@@ -159,7 +159,7 @@ namespace MediaBrowser.Api.Images
         /// </summary>
         /// <value>The id.</value>
         [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
-        public Guid Id { get; set; }
+        public string Id { get; set; }
     }
 
     /// <summary>
@@ -175,7 +175,7 @@ namespace MediaBrowser.Api.Images
         /// </summary>
         /// <value>The id.</value>
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")]
-        public Guid Id { get; set; }
+        public string Id { get; set; }
     }
 
     /// <summary>
@@ -191,7 +191,7 @@ namespace MediaBrowser.Api.Images
         /// </summary>
         /// <value>The id.</value>
         [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")]
-        public Guid Id { get; set; }
+        public string Id { get; set; }
 
         /// <summary>
         /// The raw Http Request Input Stream
@@ -206,7 +206,7 @@ namespace MediaBrowser.Api.Images
     [Route("/Items/{Id}/Images/{Type}", "POST")]
     [Route("/Items/{Id}/Images/{Type}/{Index}", "POST")]
     [Api(Description = "Posts an item image")]
-    [Authenticated]
+    [Authenticated(Roles = "admin")]
     public class PostItemImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid
     {
         /// <summary>
@@ -318,7 +318,7 @@ namespace MediaBrowser.Api.Images
 
                 try
                 {
-                    var size = _imageProcessor.GetImageSize(info.Path, info.DateModified);
+                    var size = _imageProcessor.GetImageSize(info);
 
                     width = Convert.ToInt32(size.Width);
                     height = Convert.ToInt32(size.Height);
@@ -417,11 +417,12 @@ namespace MediaBrowser.Api.Images
         /// <param name="request">The request.</param>
         public void Post(PostUserImage request)
         {
-            var id = new Guid(GetPathValue(1));
+            var userId = GetPathValue(1);
+            AssertCanUpdateUser(_userManager, userId);
 
             request.Type = (ImageType)Enum.Parse(typeof(ImageType), GetPathValue(3), true);
 
-            var item = _userManager.GetUserById(id);
+            var item = _userManager.GetUserById(userId);
 
             var task = PostImage(item, request.RequestStream, request.Type, Request.ContentType);
 
@@ -434,7 +435,7 @@ namespace MediaBrowser.Api.Images
         /// <param name="request">The request.</param>
         public void Post(PostItemImage request)
         {
-            var id = new Guid(GetPathValue(1));
+            var id = GetPathValue(1);
 
             request.Type = (ImageType)Enum.Parse(typeof(ImageType), GetPathValue(3), true);
 
@@ -451,7 +452,10 @@ namespace MediaBrowser.Api.Images
         /// <param name="request">The request.</param>
         public void Delete(DeleteUserImage request)
         {
-            var item = _userManager.GetUserById(request.Id);
+            var userId = request.Id;
+            AssertCanUpdateUser(_userManager, userId);
+
+            var item = _userManager.GetUserById(userId);
 
             var task = item.DeleteImage(request.Type, request.Index ?? 0);
 
@@ -492,7 +496,6 @@ namespace MediaBrowser.Api.Images
         /// <param name="currentIndex">Index of the current.</param>
         /// <param name="newIndex">The new index.</param>
         /// <returns>Task.</returns>
-        /// <exception cref="System.ArgumentException">The change index operation is only applicable to backdrops and screenshots</exception>
         private Task UpdateItemIndex(IHasImages item, ImageType type, int currentIndex, int newIndex)
         {
             return item.SwapImages(type, currentIndex, newIndex);
diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs
index d6b4da8bea..a0ba6e61f8 100644
--- a/MediaBrowser.Api/ItemLookupService.cs
+++ b/MediaBrowser.Api/ItemLookupService.cs
@@ -200,24 +200,15 @@ namespace MediaBrowser.Api
             //}
             item.ProviderIds = request.ProviderIds;
 
-            var service = new ItemRefreshService(_libraryManager)
+            var task = _providerManager.RefreshFullItem(item, new MetadataRefreshOptions
             {
-                Logger = Logger,
-                Request = Request,
-                ResultFactory = ResultFactory,
-                SessionContext = SessionContext,
-                AuthorizationContext = AuthorizationContext
-            };
-
-            service.Post(new RefreshItem
-            {
-                Id = request.Id,
                 MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
                 ImageRefreshMode = ImageRefreshMode.FullRefresh,
                 ReplaceAllMetadata = true,
-                ReplaceAllImages = request.ReplaceAllImages,
-                Recursive = true
-            });
+                ReplaceAllImages = request.ReplaceAllImages
+
+            }, CancellationToken.None);
+            Task.WaitAll(task);
         }
 
         /// <summary>
diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs
index 78bc14ab09..419077f212 100644
--- a/MediaBrowser.Api/ItemRefreshService.cs
+++ b/MediaBrowser.Api/ItemRefreshService.cs
@@ -1,13 +1,7 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Providers;
 using ServiceStack;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Api
 {
@@ -40,41 +34,12 @@ namespace MediaBrowser.Api
     public class ItemRefreshService : BaseApiService
     {
         private readonly ILibraryManager _libraryManager;
+        private readonly IProviderManager _providerManager;
 
-        public ItemRefreshService(ILibraryManager libraryManager)
+        public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager)
         {
             _libraryManager = libraryManager;
-        }
-
-        private async Task RefreshArtist(RefreshItem request, MusicArtist item)
-        {
-            var cancellationToken = CancellationToken.None;
-
-            var albums = _libraryManager.RootFolder
-                                        .GetRecursiveChildren()
-                                        .OfType<MusicAlbum>()
-                                        .Where(i => i.HasArtist(item.Name))
-                                        .ToList();
-
-            var musicArtists = albums
-                .Select(i => i.Parent)
-                .OfType<MusicArtist>()
-                .ToList();
-
-            var options = GetRefreshOptions(request);
-
-            var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, options, true));
-
-            await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false);
-
-            try
-            {
-                await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error refreshing library", ex);
-            }
+            _providerManager = providerManager;
         }
 
         /// <summary>
@@ -85,68 +50,9 @@ namespace MediaBrowser.Api
         {
             var item = _libraryManager.GetItemById(request.Id);
 
-            var task = item is MusicArtist ? RefreshArtist(request, (MusicArtist)item) : RefreshItem(request, item);
-
-            Task.WaitAll(task);
-        }
-
-        /// <summary>
-        /// Refreshes the item.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>Task.</returns>
-        private async Task RefreshItem(RefreshItem request, BaseItem item)
-        {
             var options = GetRefreshOptions(request);
 
-            try
-            {
-                await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
-
-                if (item.IsFolder)
-                {
-                    // Collection folders don't validate their children so we'll have to simulate that here
-                    var collectionFolder = item as CollectionFolder;
-
-                    if (collectionFolder != null)
-                    {
-                        await RefreshCollectionFolderChildren(request, collectionFolder).ConfigureAwait(false);
-                    }
-                    else
-                    {
-                        var folder = (Folder)item;
-
-                        await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, request.Recursive).ConfigureAwait(false);
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error refreshing library", ex);
-            }
-        }
-
-        /// <summary>
-        /// Refreshes the collection folder children.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <param name="collectionFolder">The collection folder.</param>
-        /// <returns>Task.</returns>
-        private async Task RefreshCollectionFolderChildren(RefreshItem request, CollectionFolder collectionFolder)
-        {
-            var options = GetRefreshOptions(request);
-
-            foreach (var child in collectionFolder.Children.ToList())
-            {
-                await child.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
-
-                if (child.IsFolder)
-                {
-                    var folder = (Folder)child;
-
-                    await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, request.Recursive).ConfigureAwait(false);
-                }
-            }
+            _providerManager.QueueRefresh(item.Id, options);
         }
 
         private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request)
diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs
index 6517d738b9..0138380915 100644
--- a/MediaBrowser.Api/ItemUpdateService.cs
+++ b/MediaBrowser.Api/ItemUpdateService.cs
@@ -41,8 +41,8 @@ namespace MediaBrowser.Api
         [ApiMember(Name = "ContentType", Description = "The content type of the item", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
         public string ContentType { get; set; }
     }
-    
-    [Authenticated]
+
+    [Authenticated(Roles = "admin")]
     public class ItemUpdateService : BaseApiService
     {
         private readonly ILibraryManager _libraryManager;
@@ -61,7 +61,7 @@ namespace MediaBrowser.Api
         public object Get(GetMetadataEditorInfo request)
         {
             var item = _libraryManager.GetItemById(request.ItemId);
-            
+
             var info = new MetadataEditorInfo
             {
                 ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(),
@@ -131,7 +131,7 @@ namespace MediaBrowser.Api
                     Value = ""
                 });
             }
-            
+
             list.Add(new NameValuePair
             {
                 Name = "FolderTypeMovies",
@@ -389,20 +389,33 @@ namespace MediaBrowser.Api
                 game.PlayersSupported = request.Players;
             }
 
-            var song = item as Audio;
+            var hasAlbumArtists = item as IHasAlbumArtist;
+            if (hasAlbumArtists != null)
+            {
+                hasAlbumArtists.AlbumArtists = request
+                    .AlbumArtists
+                    .Select(i => i.Name)
+                    .ToList();
+            }
 
+            var hasArtists = item as IHasArtist;
+            if (hasArtists != null)
+            {
+                hasArtists.Artists = request
+                    .ArtistItems
+                    .Select(i => i.Name)
+                    .ToList();
+            }
+
+            var song = item as Audio;
             if (song != null)
             {
                 song.Album = request.Album;
-                song.AlbumArtists = string.IsNullOrWhiteSpace(request.AlbumArtist) ? new List<string>() : new List<string> { request.AlbumArtist };
-                song.Artists = request.Artists.ToList();
             }
 
             var musicVideo = item as MusicVideo;
-
             if (musicVideo != null)
             {
-                musicVideo.Artists = request.Artists.ToList();
                 musicVideo.Album = request.Album;
             }
 
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 85cc879f4f..4d9afa260e 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -1,5 +1,4 @@
 using MediaBrowser.Controller.Activity;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -9,11 +8,9 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Activity;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Querying;
 using ServiceStack;
 using System;
diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index 27944a4ea7..f5fe921cec 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -212,24 +212,26 @@ namespace MediaBrowser.Api.Library
 
                     File.Create(path);
                 }
-
-                // Need to add a delay here or directory watchers may still pick up the changes
-                var task = Task.Delay(1000);
-                // Have to block here to allow exceptions to bubble
-                Task.WaitAll(task);
             }
             finally
             {
-                // No need to start if scanning the library because it will handle it
-                if (!request.RefreshLibrary)
+                Task.Run(() =>
                 {
-                    _libraryMonitor.Start();
-                }
-            }
-
-            if (request.RefreshLibrary)
-            {
-                _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    // No need to start if scanning the library because it will handle it
+                    if (request.RefreshLibrary)
+                    {
+                        _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    }
+                    else
+                    {
+                        // Need to add a delay here or directory watchers may still pick up the changes
+                        var task = Task.Delay(1000);
+                        // Have to block here to allow exceptions to bubble
+                        Task.WaitAll(task);
+                        
+                        _libraryMonitor.Start();
+                    }
+                });
             }
         }
 
@@ -279,24 +281,26 @@ namespace MediaBrowser.Api.Library
                 }
 
                 Directory.Move(currentPath, newPath);
-
-                // Need to add a delay here or directory watchers may still pick up the changes
-                var task = Task.Delay(1000);
-                // Have to block here to allow exceptions to bubble
-                Task.WaitAll(task);
             }
             finally
             {
-                // No need to start if scanning the library because it will handle it
-                if (!request.RefreshLibrary)
+                Task.Run(() =>
                 {
-                    _libraryMonitor.Start();
-                }
-            }
-
-            if (request.RefreshLibrary)
-            {
-                _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    // No need to start if scanning the library because it will handle it
+                    if (request.RefreshLibrary)
+                    {
+                        _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    }
+                    else
+                    {
+                        // Need to add a delay here or directory watchers may still pick up the changes
+                        var task = Task.Delay(1000);
+                        // Have to block here to allow exceptions to bubble
+                        Task.WaitAll(task);
+
+                        _libraryMonitor.Start();
+                    }
+                });
             }
         }
 
@@ -325,24 +329,26 @@ namespace MediaBrowser.Api.Library
             try
             {
                 _fileSystem.DeleteDirectory(path, true);
-
-                // Need to add a delay here or directory watchers may still pick up the changes
-                var delayTask = Task.Delay(1000);
-                // Have to block here to allow exceptions to bubble
-                Task.WaitAll(delayTask);
             }
             finally
             {
-                // No need to start if scanning the library because it will handle it
-                if (!request.RefreshLibrary)
+                Task.Run(() =>
                 {
-                    _libraryMonitor.Start();
-                }
-            }
-
-            if (request.RefreshLibrary)
-            {
-                _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    // No need to start if scanning the library because it will handle it
+                    if (request.RefreshLibrary)
+                    {
+                        _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    }
+                    else
+                    {
+                        // Need to add a delay here or directory watchers may still pick up the changes
+                        var task = Task.Delay(1000);
+                        // Have to block here to allow exceptions to bubble
+                        Task.WaitAll(task);
+
+                        _libraryMonitor.Start();
+                    }
+                });
             }
         }
 
@@ -362,24 +368,26 @@ namespace MediaBrowser.Api.Library
             try
             {
                 LibraryHelpers.AddMediaPath(_fileSystem, request.Name, request.Path, _appPaths);
-
-                // Need to add a delay here or directory watchers may still pick up the changes
-                var task = Task.Delay(1000);
-                // Have to block here to allow exceptions to bubble
-                Task.WaitAll(task);
             }
             finally
             {
-                // No need to start if scanning the library because it will handle it
-                if (!request.RefreshLibrary)
+                Task.Run(() =>
                 {
-                    _libraryMonitor.Start();
-                }
-            }
-
-            if (request.RefreshLibrary)
-            {
-                _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    // No need to start if scanning the library because it will handle it
+                    if (request.RefreshLibrary)
+                    {
+                        _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    }
+                    else
+                    {
+                        // Need to add a delay here or directory watchers may still pick up the changes
+                        var task = Task.Delay(1000);
+                        // Have to block here to allow exceptions to bubble
+                        Task.WaitAll(task);
+
+                        _libraryMonitor.Start();
+                    }
+                });
             }
         }
 
@@ -399,24 +407,26 @@ namespace MediaBrowser.Api.Library
             try
             {
                 LibraryHelpers.RemoveMediaPath(_fileSystem, request.Name, request.Path, _appPaths);
-
-                // Need to add a delay here or directory watchers may still pick up the changes
-                var task = Task.Delay(1000);
-                // Have to block here to allow exceptions to bubble
-                Task.WaitAll(task);
             }
             finally
             {
-                // No need to start if scanning the library because it will handle it
-                if (!request.RefreshLibrary)
+                Task.Run(() =>
                 {
-                    _libraryMonitor.Start();
-                }
-            }
-
-            if (request.RefreshLibrary)
-            {
-                _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    // No need to start if scanning the library because it will handle it
+                    if (request.RefreshLibrary)
+                    {
+                        _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None);
+                    }
+                    else
+                    {
+                        // Need to add a delay here or directory watchers may still pick up the changes
+                        var task = Task.Delay(1000);
+                        // Have to block here to allow exceptions to bubble
+                        Task.WaitAll(task);
+
+                        _libraryMonitor.Start();
+                    }
+                });
             }
         }
     }
diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs
index f3dcf57e03..24c91e172f 100644
--- a/MediaBrowser.Api/LiveTv/LiveTvService.cs
+++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs
@@ -171,6 +171,9 @@ namespace MediaBrowser.Api.LiveTv
         [ApiMember(Name = "MinStartDate", Description = "Optional. The minimum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
         public string MinStartDate { get; set; }
 
+        [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? HasAired { get; set; }
+
         [ApiMember(Name = "MaxStartDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
         public string MaxStartDate { get; set; }
 
@@ -179,6 +182,24 @@ namespace MediaBrowser.Api.LiveTv
 
         [ApiMember(Name = "MaxEndDate", Description = "Optional. The maximum premiere date. Format = ISO", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
         public string MaxEndDate { get; set; }
+
+        [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
+        public bool? IsMovie { get; set; }
+
+        [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? StartIndex { get; set; }
+
+        [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public int? Limit { get; set; }
+
+        [ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Name, StartDate", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string SortBy { get; set; }
+
+        [ApiMember(Name = "SortOrder", Description = "Sort Order - Ascending,Descending", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public SortOrder? SortOrder { get; set; }
+
+        [ApiMember(Name = "Genres", Description = "The genres to return guide information for.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET,POST")]
+        public string Genres { get; set; }
     }
 
     [Route("/LiveTv/Programs/Recommended", "GET", Summary = "Gets available live tv epgs..")]
@@ -196,6 +217,9 @@ namespace MediaBrowser.Api.LiveTv
 
         [ApiMember(Name = "HasAired", Description = "Optional. Filter by programs that have completed airing, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? HasAired { get; set; }
+
+        [ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? IsMovie { get; set; }
     }
 
     [Route("/LiveTv/Programs/{Id}", "GET", Summary = "Gets a live tv program")]
@@ -312,7 +336,7 @@ namespace MediaBrowser.Api.LiveTv
 
         private void AssertUserCanManageLiveTv()
         {
-            var user = SessionContext.GetUser(Request);
+            var user = SessionContext.GetUser(Request).Result;
 
             if (user == null)
             {
@@ -368,8 +392,9 @@ namespace MediaBrowser.Api.LiveTv
         {
             var query = new ProgramQuery
             {
-                ChannelIdList = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(),
-                UserId = request.UserId
+                ChannelIds = (request.ChannelIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToArray(),
+                UserId = request.UserId,
+                HasAired = request.HasAired
             };
 
             if (!string.IsNullOrEmpty(request.MinStartDate))
@@ -392,6 +417,13 @@ namespace MediaBrowser.Api.LiveTv
                 query.MaxEndDate = DateTime.Parse(request.MaxEndDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime();
             }
 
+            query.StartIndex = request.StartIndex;
+            query.Limit = request.Limit;
+            query.SortBy = (request.SortBy ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+            query.SortOrder = request.SortOrder;
+            query.IsMovie = request.IsMovie;
+            query.Genres = (request.Genres ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
             var result = await _liveTvManager.GetPrograms(query, CancellationToken.None).ConfigureAwait(false);
 
             return ToOptimizedSerializedResultUsingCache(result);
@@ -404,7 +436,8 @@ namespace MediaBrowser.Api.LiveTv
                 UserId = request.UserId,
                 IsAiring = request.IsAiring,
                 Limit = request.Limit,
-                HasAired = request.HasAired
+                HasAired = request.HasAired,
+                IsMovie = request.IsMovie
             };
 
             var result = await _liveTvManager.GetRecommendedPrograms(query, CancellationToken.None).ConfigureAwait(false);
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 2713059212..14d0f13fb7 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -79,8 +79,10 @@
     <Compile Include="FilterService.cs" />
     <Compile Include="IHasDtoOptions.cs" />
     <Compile Include="Library\ChapterService.cs" />
-    <Compile Include="Playback\Hls\MpegDashService.cs" />
+    <Compile Include="Playback\Dash\ManifestBuilder.cs" />
+    <Compile Include="Playback\Dash\MpegDashService.cs" />
     <Compile Include="Playback\MediaInfoService.cs" />
+    <Compile Include="Playback\TranscodingThrottler.cs" />
     <Compile Include="PlaylistService.cs" />
     <Compile Include="Reports\ReportFieldType.cs" />
     <Compile Include="Reports\ReportResult.cs" />
@@ -134,6 +136,7 @@
     <Compile Include="SearchService.cs" />
     <Compile Include="Session\SessionsService.cs" />
     <Compile Include="SimilarItemsHelper.cs" />
+    <Compile Include="Sync\SyncHelper.cs" />
     <Compile Include="Sync\SyncJobWebSocketListener.cs" />
     <Compile Include="Sync\SyncJobsWebSocketListener.cs" />
     <Compile Include="Sync\SyncService.cs" />
diff --git a/MediaBrowser.Api/Music/AlbumsService.cs b/MediaBrowser.Api/Music/AlbumsService.cs
index 76c6c57764..a1c98addbe 100644
--- a/MediaBrowser.Api/Music/AlbumsService.cs
+++ b/MediaBrowser.Api/Music/AlbumsService.cs
@@ -77,15 +77,13 @@ namespace MediaBrowser.Api.Music
             var album1 = (MusicAlbum)item1;
             var album2 = (MusicAlbum)item2;
 
-            var artists1 = album1.GetRecursiveChildren(i => i is IHasArtist)
-                .Cast<IHasArtist>()
-                .SelectMany(i => i.AllArtists)
+            var artists1 = album1
+                .AllArtists
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToList();
 
-            var artists2 = album2.GetRecursiveChildren(i => i is IHasArtist)
-                .Cast<IHasArtist>()
-                .SelectMany(i => i.AllArtists)
+            var artists2 = album2
+                .AllArtists
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
 
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 49d5f1c8d8..7115ddffdb 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,9 +1,9 @@
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -14,6 +14,7 @@ using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
 using System;
@@ -68,17 +69,21 @@ namespace MediaBrowser.Api.Playback
         protected ILiveTvManager LiveTvManager { get; private set; }
         protected IDlnaManager DlnaManager { get; private set; }
         protected IDeviceManager DeviceManager { get; private set; }
-        protected IChannelManager ChannelManager { get; private set; }
         protected ISubtitleEncoder SubtitleEncoder { get; private set; }
+        protected IProcessManager ProcessManager { get; private set; }
+        protected IMediaSourceManager MediaSourceManager { get; private set; }
+        protected IZipClient ZipClient { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// </summary>
-        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager)
+        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
         {
+            ZipClient = zipClient;
+            MediaSourceManager = mediaSourceManager;
+            ProcessManager = processManager;
             DeviceManager = deviceManager;
             SubtitleEncoder = subtitleEncoder;
-            ChannelManager = channelManager;
             DlnaManager = dlnaManager;
             LiveTvManager = liveTvManager;
             FileSystem = fileSystem;
@@ -129,9 +134,21 @@ namespace MediaBrowser.Api.Playback
             var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
 
             data += "-" + (state.Request.DeviceId ?? string.Empty);
-            data += "-" + (state.Request.ClientTime ?? string.Empty);
+            data += "-" + (state.Request.StreamId ?? state.Request.ClientTime ?? string.Empty);
+
+            var dataHash = data.GetMD5().ToString("N");
+
+            if (EnableOutputInSubFolder)
+            {
+                return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLower());
+            }
+
+            return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLower());
+        }
 
-            return Path.Combine(folder, data.GetMD5().ToString("N") + (outputFileExtension ?? string.Empty).ToLower());
+        protected virtual bool EnableOutputInSubFolder
+        {
+            get { return false; }
         }
 
         protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@@ -877,14 +894,6 @@ namespace MediaBrowser.Api.Playback
             return "copy";
         }
 
-        private bool SupportsThrottleWithStream
-        {
-            get
-            {
-                return false;
-            }
-        }
-
         /// <summary>
         /// Gets the input argument.
         /// </summary>
@@ -908,23 +917,15 @@ namespace MediaBrowser.Api.Playback
 
         private string GetInputPathArgument(string transcodingJobId, StreamState state)
         {
-            if (state.InputProtocol == MediaProtocol.File &&
-               state.RunTimeTicks.HasValue &&
-               state.VideoType == VideoType.VideoFile &&
-               !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            {
-                if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
-                {
-                    if (SupportsThrottleWithStream)
-                    {
-                        var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
-
-                        url += "&transcodingJobId=" + transcodingJobId;
-
-                        return string.Format("\"{0}\"", url);
-                    }
-                }
-            }
+            //if (state.InputProtocol == MediaProtocol.File &&
+            //   state.RunTimeTicks.HasValue &&
+            //   state.VideoType == VideoType.VideoFile &&
+            //   !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+            //{
+            //    if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
+            //    {
+            //    }
+            //}
 
             var protocol = state.InputProtocol;
 
@@ -1053,6 +1054,7 @@ namespace MediaBrowser.Api.Playback
             }
 
             var transcodingJob = ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath,
+                state.Request.StreamId ?? state.Request.ClientTime,
                 transcodingId,
                 TranscodingJobType,
                 process,
@@ -1094,7 +1096,7 @@ namespace MediaBrowser.Api.Playback
             StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream);
 
             // Wait for the file to exist before proceeeding
-            while (!File.Exists(outputPath) && !transcodingJob.HasExited)
+            while (!File.Exists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
             {
                 await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
             }
@@ -1109,9 +1111,26 @@ namespace MediaBrowser.Api.Playback
                 }
             }
 
+            StartThrottler(state, transcodingJob);
+
             return transcodingJob;
         }
 
+        private void StartThrottler(StreamState state, TranscodingJob transcodingJob)
+        {
+            if (state.InputProtocol == MediaProtocol.File &&
+                           state.RunTimeTicks.HasValue &&
+                           state.VideoType == VideoType.VideoFile &&
+                           !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
+            {
+                if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
+                {
+                    state.TranscodingThrottler = new TranscodingThrottler(transcodingJob, Logger, ProcessManager);
+                    state.TranscodingThrottler.Start();
+                }
+            }
+        }
+
         private async void StartStreamingLog(TranscodingJob transcodingJob, StreamState state, Stream source, Stream target)
         {
             try
@@ -1505,7 +1524,7 @@ namespace MediaBrowser.Api.Playback
                 }
                 else if (i == 16)
                 {
-                    request.ClientTime = val;
+                    request.StreamId = val;
                 }
                 else if (i == 17)
                 {
@@ -1640,6 +1659,9 @@ namespace MediaBrowser.Api.Playback
             List<MediaStream> mediaStreams = null;
 
             state.ItemType = item.GetType().Name;
+            state.ItemId = item.Id.ToString("N");
+            var archivable = item as IArchivable;
+            state.IsInputArchive = archivable != null && archivable.IsArchive;
 
             if (item is ILiveTvRecording)
             {
@@ -1653,7 +1675,7 @@ namespace MediaBrowser.Api.Playback
 
                 var source = string.IsNullOrEmpty(request.MediaSourceId)
                     ? recording.GetMediaSources(false).First()
-                    : recording.GetMediaSources(false).First(i => string.Equals(i.Id, request.MediaSourceId));
+                    : MediaSourceManager.GetStaticMediaSource(recording, request.MediaSourceId, false);
 
                 mediaStreams = source.MediaStreams;
 
@@ -1692,25 +1714,13 @@ namespace MediaBrowser.Api.Playback
                 // Just to prevent this from being null and causing other methods to fail
                 state.MediaPath = string.Empty;
             }
-            else if (item is IChannelMediaItem)
-            {
-                var mediaSource = await GetChannelMediaInfo(request.Id, request.MediaSourceId, cancellationToken).ConfigureAwait(false);
-                state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-                state.InputProtocol = mediaSource.Protocol;
-                state.MediaPath = mediaSource.Path;
-                state.RunTimeTicks = item.RunTimeTicks;
-                state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
-                state.InputBitrate = mediaSource.Bitrate;
-                state.InputFileSize = mediaSource.Size;
-                state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
-                mediaStreams = mediaSource.MediaStreams;
-            }
             else
             {
-                var hasMediaSources = (IHasMediaSources)item;
+                var mediaSources = await MediaSourceManager.GetPlayackMediaSources(request.Id, false, cancellationToken).ConfigureAwait(false);
+
                 var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
-                    ? hasMediaSources.GetMediaSources(false).First()
-                    : hasMediaSources.GetMediaSources(false).First(i => string.Equals(i.Id, request.MediaSourceId));
+                    ? mediaSources.First()
+                    : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
 
                 mediaStreams = mediaSource.MediaStreams;
 
@@ -1720,6 +1730,8 @@ namespace MediaBrowser.Api.Playback
                 state.InputFileSize = mediaSource.Size;
                 state.InputBitrate = mediaSource.Bitrate;
                 state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+                state.RunTimeTicks = mediaSource.RunTimeTicks;
+                state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
 
                 var video = item as Video;
 
@@ -1742,7 +1754,6 @@ namespace MediaBrowser.Api.Playback
                     }
                 }
 
-                state.RunTimeTicks = mediaSource.RunTimeTicks;
             }
 
             var videoRequest = request as VideoStreamRequest;
@@ -1865,29 +1876,6 @@ namespace MediaBrowser.Api.Playback
             state.AllMediaStreams = mediaStreams;
         }
 
-        private async Task<MediaSourceInfo> GetChannelMediaInfo(string id,
-            string mediaSourceId,
-            CancellationToken cancellationToken)
-        {
-            var channelMediaSources = await ChannelManager.GetChannelItemMediaSources(id, true, cancellationToken)
-                .ConfigureAwait(false);
-
-            var list = channelMediaSources.ToList();
-
-            if (!string.IsNullOrWhiteSpace(mediaSourceId))
-            {
-                var source = list
-                    .FirstOrDefault(i => string.Equals(mediaSourceId, i.Id));
-
-                if (source != null)
-                {
-                    return source;
-                }
-            }
-
-            return list.First();
-        }
-
         private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
         {
             if (videoStream.IsInterlaced)
diff --git a/MediaBrowser.Api/Playback/Dash/ManifestBuilder.cs b/MediaBrowser.Api/Playback/Dash/ManifestBuilder.cs
new file mode 100644
index 0000000000..35e252a198
--- /dev/null
+++ b/MediaBrowser.Api/Playback/Dash/ManifestBuilder.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Globalization;
+using System.Security;
+using System.Text;
+
+namespace MediaBrowser.Api.Playback.Dash
+{
+    public class ManifestBuilder
+    {
+        protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
+
+        public string GetManifestText(StreamState state, string playlistUrl)
+        {
+            var builder = new StringBuilder();
+
+            var time = TimeSpan.FromTicks(state.RunTimeTicks.Value);
+
+            var duration = "PT" + time.Hours.ToString("00", UsCulture) + "H" + time.Minutes.ToString("00", UsCulture) + "M" + time.Seconds.ToString("00", UsCulture) + ".00S";
+
+            builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+
+            builder.AppendFormat(
+                "<MPD xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\" profiles=\"urn:mpeg:dash:profile:isoff-live:2011\" type=\"static\" mediaPresentationDuration=\"{0}\" minBufferTime=\"PT5.0S\">",
+                duration);
+
+            builder.Append("<ProgramInformation>");
+            builder.Append("</ProgramInformation>");
+
+            builder.Append("<Period start=\"PT0S\">");
+            builder.Append(GetVideoAdaptationSet(state, playlistUrl));
+            builder.Append(GetAudioAdaptationSet(state, playlistUrl));
+            builder.Append("</Period>");
+
+            builder.Append("</MPD>");
+
+            return builder.ToString();
+        }
+
+        private string GetVideoAdaptationSet(StreamState state, string playlistUrl)
+        {
+            var builder = new StringBuilder();
+
+            builder.Append("<AdaptationSet id=\"video\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">");
+            builder.Append(GetVideoRepresentationOpenElement(state));
+
+            AppendSegmentList(state, builder, "0", playlistUrl);
+
+            builder.Append("</Representation>");
+            builder.Append("</AdaptationSet>");
+
+            return builder.ToString();
+        }
+
+        private string GetAudioAdaptationSet(StreamState state, string playlistUrl)
+        {
+            var builder = new StringBuilder();
+
+            builder.Append("<AdaptationSet id=\"audio\" segmentAlignment=\"true\" bitstreamSwitching=\"true\">");
+            builder.Append(GetAudioRepresentationOpenElement(state));
+
+            builder.Append("<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"6\" />");
+
+            AppendSegmentList(state, builder, "1", playlistUrl);
+
+            builder.Append("</Representation>");
+            builder.Append("</AdaptationSet>");
+
+            return builder.ToString();
+        }
+
+        private string GetVideoRepresentationOpenElement(StreamState state)
+        {
+            var codecs = GetVideoCodecDescriptor(state);
+
+            var mime = "video/mp4";
+
+            var xml = "<Representation id=\"0\" mimeType=\"" + mime + "\" codecs=\"" + codecs + "\"";
+
+            if (state.OutputWidth.HasValue)
+            {
+                xml += " width=\"" + state.OutputWidth.Value.ToString(UsCulture) + "\"";
+            }
+            if (state.OutputHeight.HasValue)
+            {
+                xml += " height=\"" + state.OutputHeight.Value.ToString(UsCulture) + "\"";
+            }
+            if (state.OutputVideoBitrate.HasValue)
+            {
+                xml += " bandwidth=\"" + state.OutputVideoBitrate.Value.ToString(UsCulture) + "\"";
+            }
+
+            xml += ">";
+
+            return xml;
+        }
+
+        private string GetAudioRepresentationOpenElement(StreamState state)
+        {
+            var codecs = GetAudioCodecDescriptor(state);
+
+            var mime = "audio/mp4";
+
+            var xml = "<Representation id=\"1\" mimeType=\"" + mime + "\" codecs=\"" + codecs + "\"";
+
+            if (state.OutputAudioSampleRate.HasValue)
+            {
+                xml += " audioSamplingRate=\"" + state.OutputAudioSampleRate.Value.ToString(UsCulture) + "\"";
+            }
+            if (state.OutputAudioBitrate.HasValue)
+            {
+                xml += " bandwidth=\"" + state.OutputAudioBitrate.Value.ToString(UsCulture) + "\"";
+            }
+
+            xml += ">";
+
+            return xml;
+        }
+
+        private string GetVideoCodecDescriptor(StreamState state)
+        {
+            // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
+            // http://www.chipwreck.de/blog/2010/02/25/html-5-video-tag-and-attributes/
+
+            var level = state.TargetVideoLevel ?? 0;
+            var profile = state.TargetVideoProfile ?? string.Empty;
+
+            if (profile.IndexOf("high", StringComparison.OrdinalIgnoreCase) != -1)
+            {
+                if (level >= 4.1)
+                {
+                    return "avc1.640028";
+                }
+
+                if (level >= 4)
+                {
+                    return "avc1.640028";
+                }
+
+                return "avc1.64001f";
+            }
+
+            if (profile.IndexOf("main", StringComparison.OrdinalIgnoreCase) != -1)
+            {
+                if (level >= 4)
+                {
+                    return "avc1.4d0028";
+                }
+
+                if (level >= 3.1)
+                {
+                    return "avc1.4d001f";
+                }
+
+                return "avc1.4d001e";
+            }
+
+            if (level >= 3.1)
+            {
+                return "avc1.42001f";
+            }
+
+            return "avc1.42E01E";
+        }
+
+        private string GetAudioCodecDescriptor(StreamState state)
+        {
+            // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
+
+            if (string.Equals(state.OutputAudioCodec, "mp3", StringComparison.OrdinalIgnoreCase))
+            {
+                return "mp4a.40.34";
+            }
+
+            // AAC 5ch
+            if (state.OutputAudioChannels.HasValue && state.OutputAudioChannels.Value >= 5)
+            {
+                return "mp4a.40.5";
+            }
+
+            // AAC 2ch
+            return "mp4a.40.2";
+        }
+
+        private void AppendSegmentList(StreamState state, StringBuilder builder, string type, string playlistUrl)
+        {
+            var extension = ".m4s";
+
+            var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
+
+            var queryStringIndex = playlistUrl.IndexOf('?');
+            var queryString = queryStringIndex == -1 ? string.Empty : playlistUrl.Substring(queryStringIndex);
+
+            var index = 0;
+            var duration = 1000000 * state.SegmentLength;
+            builder.AppendFormat("<SegmentList timescale=\"1000000\" duration=\"{0}\" startNumber=\"1\">", duration.ToString(CultureInfo.InvariantCulture));
+
+            while (seconds > 0)
+            {
+                var filename = index == 0
+                    ? "init"
+                    : (index - 1).ToString(UsCulture);
+
+                var segmentUrl = string.Format("dash/{3}/{0}{1}{2}",
+                    filename,
+                    extension,
+                    SecurityElement.Escape(queryString),
+                    type);
+
+                if (index == 0)
+                {
+                    builder.AppendFormat("<Initialization sourceURL=\"{0}\"/>", segmentUrl);
+                }
+                else
+                {
+                    builder.AppendFormat("<SegmentURL media=\"{0}\"/>", segmentUrl);
+                }
+
+                seconds -= state.SegmentLength;
+                index++;
+            }
+            builder.Append("</SegmentList>");
+        }
+    }
+}
diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
new file mode 100644
index 0000000000..38b0d35d11
--- /dev/null
+++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
@@ -0,0 +1,561 @@
+using MediaBrowser.Api.Playback.Hls;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.IO;
+using ServiceStack;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
+
+namespace MediaBrowser.Api.Playback.Dash
+{
+    /// <summary>
+    /// Options is needed for chromecast. Threw Head in there since it's related
+    /// </summary>
+    [Route("/Videos/{Id}/master.mpd", "GET", Summary = "Gets a video stream using Mpeg dash.")]
+    [Route("/Videos/{Id}/master.mpd", "HEAD", Summary = "Gets a video stream using Mpeg dash.")]
+    public class GetMasterManifest : VideoStreamRequest
+    {
+        public bool EnableAdaptiveBitrateStreaming { get; set; }
+
+        public GetMasterManifest()
+        {
+            EnableAdaptiveBitrateStreaming = true;
+        }
+    }
+
+    [Route("/Videos/{Id}/dash/{RepresentationId}/{SegmentId}.m4s", "GET")]
+    public class GetDashSegment : VideoStreamRequest
+    {
+        /// <summary>
+        /// Gets or sets the segment id.
+        /// </summary>
+        /// <value>The segment id.</value>
+        public string SegmentId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the representation identifier.
+        /// </summary>
+        /// <value>The representation identifier.</value>
+        public string RepresentationId { get; set; }
+    }
+
+    public class MpegDashService : BaseHlsService
+    {
+        public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient)
+        {
+            NetworkManager = networkManager;
+        }
+
+        protected INetworkManager NetworkManager { get; private set; }
+
+        public object Get(GetMasterManifest request)
+        {
+            var result = GetAsync(request, "GET").Result;
+
+            return result;
+        }
+
+        public object Head(GetMasterManifest request)
+        {
+            var result = GetAsync(request, "HEAD").Result;
+
+            return result;
+        }
+
+        protected override bool EnableOutputInSubFolder
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        private async Task<object> GetAsync(GetMasterManifest request, string method)
+        {
+            if (string.IsNullOrEmpty(request.MediaSourceId))
+            {
+                throw new ArgumentException("MediaSourceId is required");
+            }
+
+            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
+
+            var playlistText = string.Empty;
+
+            if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase))
+            {
+                playlistText = new ManifestBuilder().GetManifestText(state, Request.RawUrl);
+            }
+
+            return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.mpd"), new Dictionary<string, string>());
+        }
+
+        public object Get(GetDashSegment request)
+        {
+            return GetDynamicSegment(request, request.SegmentId, request.RepresentationId).Result;
+        }
+
+        private async Task<object> GetDynamicSegment(VideoStreamRequest request, string segmentId, string representationId)
+        {
+            if ((request.StartTimeTicks ?? 0) > 0)
+            {
+                throw new ArgumentException("StartTimeTicks is not allowed.");
+            }
+
+            var cancellationTokenSource = new CancellationTokenSource();
+            var cancellationToken = cancellationTokenSource.Token;
+
+            var requestedIndex = string.Equals(segmentId, "init", StringComparison.OrdinalIgnoreCase) ?
+                -1 :
+                int.Parse(segmentId, NumberStyles.Integer, UsCulture);
+
+            var state = await GetState(request, cancellationToken).ConfigureAwait(false);
+
+            var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".mpd");
+
+            var segmentExtension = GetSegmentFileExtension(state);
+
+            var segmentPath = FindSegment(playlistPath, representationId, segmentExtension, requestedIndex);
+            var segmentLength = state.SegmentLength;
+
+            TranscodingJob job = null;
+
+            if (!string.IsNullOrWhiteSpace(segmentPath))
+            {
+                job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
+                return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
+            }
+
+            await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
+            try
+            {
+                segmentPath = FindSegment(playlistPath, representationId, segmentExtension, requestedIndex);
+                if (!string.IsNullOrWhiteSpace(segmentPath))
+                {
+                    job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
+                    return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
+                }
+                else
+                {
+                    if (string.Equals(representationId, "0", StringComparison.OrdinalIgnoreCase))
+                    {
+                        job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
+                        var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
+                        var segmentGapRequiringTranscodingChange = 24 / state.SegmentLength;
+                        Logger.Debug("Current transcoding index is {0}. requestedIndex={1}. segmentGapRequiringTranscodingChange={2}", currentTranscodingIndex ?? -2, requestedIndex, segmentGapRequiringTranscodingChange);
+                        if (currentTranscodingIndex == null || requestedIndex < currentTranscodingIndex.Value || (requestedIndex - currentTranscodingIndex.Value) > segmentGapRequiringTranscodingChange)
+                        {
+                            // If the playlist doesn't already exist, startup ffmpeg
+                            try
+                            {
+                                ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.StreamId, p => false);
+
+                                if (currentTranscodingIndex.HasValue)
+                                {
+                                    DeleteLastTranscodedFiles(playlistPath, 0);
+                                }
+
+                                var positionTicks = GetPositionTicks(state, requestedIndex);
+                                request.StartTimeTicks = positionTicks;
+
+                                var startNumber = GetStartNumber(state);
+
+                                var workingDirectory = Path.Combine(Path.GetDirectoryName(playlistPath), (startNumber == -1 ? 0 : startNumber).ToString(CultureInfo.InvariantCulture));
+                                state.WaitForPath = Path.Combine(workingDirectory, Path.GetFileName(playlistPath));
+                                Directory.CreateDirectory(workingDirectory);
+                                job = await StartFfMpeg(state, playlistPath, cancellationTokenSource, workingDirectory).ConfigureAwait(false);
+                                await WaitForMinimumDashSegmentCount(Path.Combine(workingDirectory, Path.GetFileName(playlistPath)), 1, cancellationTokenSource.Token).ConfigureAwait(false);
+                            }
+                            catch
+                            {
+                                state.Dispose();
+                                throw;
+                            }
+                        }
+                    }
+                }
+            }
+            finally
+            {
+                ApiEntryPoint.Instance.TranscodingStartLock.Release();
+            }
+
+            while (string.IsNullOrWhiteSpace(segmentPath))
+            {
+                segmentPath = FindSegment(playlistPath, representationId, segmentExtension, requestedIndex);
+                await Task.Delay(50, cancellationToken).ConfigureAwait(false);
+            }
+
+            Logger.Info("returning {0}", segmentPath);
+            return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job ?? ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType), cancellationToken).ConfigureAwait(false);
+        }
+
+        private long GetPositionTicks(StreamState state, int requestedIndex)
+        {
+            if (requestedIndex <= 0)
+            {
+                return 0;
+            }
+
+            var startSeconds = requestedIndex * state.SegmentLength;
+            return TimeSpan.FromSeconds(startSeconds).Ticks;
+        }
+
+        protected  Task WaitForMinimumDashSegmentCount(string playlist, int segmentCount, CancellationToken cancellationToken)
+        {
+            return WaitForSegment(playlist, "stream0-" + segmentCount.ToString("00000", CultureInfo.InvariantCulture) + ".m4s", cancellationToken);
+        }
+
+        private async Task<object> GetSegmentResult(string playlistPath,
+            string segmentPath,
+            int segmentIndex,
+            int segmentLength,
+            TranscodingJob transcodingJob,
+            CancellationToken cancellationToken)
+        {
+            // If all transcoding has completed, just return immediately
+            if (transcodingJob != null && transcodingJob.HasExited)
+            {
+                return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
+            }
+
+            // Wait for the file to stop being written to, then stream it
+            var length = new FileInfo(segmentPath).Length;
+            var eofCount = 0;
+
+            while (eofCount < 10)
+            {
+                var info = new FileInfo(segmentPath);
+
+                if (!info.Exists)
+                {
+                    break;
+                }
+
+                var newLength = info.Length;
+
+                if (newLength == length)
+                {
+                    eofCount++;
+                }
+                else
+                {
+                    eofCount = 0;
+                }
+
+                length = newLength;
+                await Task.Delay(100, cancellationToken).ConfigureAwait(false);
+            }
+
+            return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
+        }
+
+        private object GetSegmentResult(string segmentPath, int index, int segmentLength, TranscodingJob transcodingJob)
+        {
+            var segmentEndingSeconds = (1 + index) * segmentLength;
+            var segmentEndingPositionTicks = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks;
+
+            return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+            {
+                Path = segmentPath,
+                FileShare = FileShare.ReadWrite,
+                OnComplete = () =>
+                {
+                    if (transcodingJob != null)
+                    {
+                        transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
+                    }
+
+                }
+            });
+        }
+
+        public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
+        {
+            var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType);
+
+            if (job == null || job.HasExited)
+            {
+                return null;
+            }
+
+            var file = GetLastTranscodingFiles(playlist, segmentExtension, FileSystem, 1).FirstOrDefault();
+
+            if (file == null)
+            {
+                return null;
+            }
+
+            return GetIndex(file.FullName);
+        }
+
+        public int GetIndex(string segmentPath)
+        {
+            var indexString = Path.GetFileNameWithoutExtension(segmentPath).Split('-').LastOrDefault();
+
+            if (string.Equals(indexString, "init", StringComparison.OrdinalIgnoreCase))
+            {
+                return -1;
+            }
+            var startNumber = int.Parse(Path.GetFileNameWithoutExtension(Path.GetDirectoryName(segmentPath)), NumberStyles.Integer, UsCulture);
+
+            return startNumber + int.Parse(indexString, NumberStyles.Integer, UsCulture) - 1;
+        }
+
+        private void DeleteLastTranscodedFiles(string playlistPath, int retryCount)
+        {
+            if (retryCount >= 5)
+            {
+                return;
+            }
+        }
+
+        private static List<FileInfo> GetLastTranscodingFiles(string playlist, string segmentExtension, IFileSystem fileSystem, int count)
+        {
+            var folder = Path.GetDirectoryName(playlist);
+
+            try
+            {
+                return new DirectoryInfo(folder)
+                    .EnumerateFiles("*", SearchOption.AllDirectories)
+                    .Where(i => string.Equals(i.Extension, segmentExtension, StringComparison.OrdinalIgnoreCase))
+                    .OrderByDescending(fileSystem.GetLastWriteTimeUtc)
+                    .Take(count)
+                    .ToList();
+            }
+            catch (DirectoryNotFoundException)
+            {
+                return new List<FileInfo>();
+            }
+        }
+
+        private string FindSegment(string playlist, string representationId, string segmentExtension, int requestedIndex)
+        {
+            var folder = Path.GetDirectoryName(playlist);
+
+            if (requestedIndex == -1)
+            {
+                var path = Path.Combine(folder, "0", "stream" + representationId + "-" + "init" + segmentExtension);
+                return File.Exists(path) ? path : null;
+            }
+
+            try
+            {
+                foreach (var subfolder in new DirectoryInfo(folder).EnumerateDirectories().ToList())
+                {
+                    var subfolderName = Path.GetFileNameWithoutExtension(subfolder.FullName);
+                    int startNumber;
+                    if (int.TryParse(subfolderName, NumberStyles.Any, UsCulture, out startNumber))
+                    {
+                        var segmentIndex = requestedIndex - startNumber + 1;
+                        var path = Path.Combine(folder, subfolderName, "stream" + representationId + "-" + segmentIndex.ToString("00000", CultureInfo.InvariantCulture) + segmentExtension);
+                        if (File.Exists(path))
+                        {
+                            return path;
+                        }
+                    }
+                }
+            }
+            catch (DirectoryNotFoundException)
+            {
+                
+            }
+
+            return null;
+        }
+
+        protected override string GetAudioArguments(StreamState state)
+        {
+            var codec = state.OutputAudioCodec;
+
+            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
+            {
+                return "-codec:a:0 copy";
+            }
+
+            var args = "-codec:a:0 " + codec;
+
+            var channels = state.OutputAudioChannels;
+
+            if (channels.HasValue)
+            {
+                args += " -ac " + channels.Value;
+            }
+
+            var bitrate = state.OutputAudioBitrate;
+
+            if (bitrate.HasValue)
+            {
+                args += " -ab " + bitrate.Value.ToString(UsCulture);
+            }
+
+            args += " " + GetAudioFilterParam(state, true);
+
+            return args;
+        }
+
+        protected override string GetVideoArguments(StreamState state)
+        {
+            var codec = state.OutputVideoCodec;
+
+            var args = "-codec:v:0 " + codec;
+
+            if (state.EnableMpegtsM2TsMode)
+            {
+                args += " -mpegts_m2ts_mode 1";
+            }
+
+            // See if we can save come cpu cycles by avoiding encoding
+            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
+            {
+                return state.VideoStream != null && IsH264(state.VideoStream) ?
+                    args + " -bsf:v h264_mp4toannexb" :
+                    args;
+            }
+
+            var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
+                state.SegmentLength.ToString(UsCulture));
+
+            var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
+
+            args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
+
+            // Add resolution params, if specified
+            if (!hasGraphicalSubs)
+            {
+                args += GetOutputSizeParam(state, codec, false);
+            }
+
+            // This is for internal graphical subs
+            if (hasGraphicalSubs)
+            {
+                args += GetGraphicalSubtitleParam(state, codec);
+            }
+
+            return args;
+        }
+
+        protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
+        {
+            // test url http://192.168.1.2:8096/videos/233e8905d559a8f230db9bffd2ac9d6d/master.mpd?mediasourceid=233e8905d559a8f230db9bffd2ac9d6d&videocodec=h264&audiocodec=aac&maxwidth=1280&videobitrate=500000&audiobitrate=128000&profile=baseline&level=3
+            // Good info on i-frames http://blog.streamroot.io/encode-multi-bitrate-videos-mpeg-dash-mse-based-media-players/
+
+            var threads = GetNumberOfThreads(state, false);
+
+            var inputModifier = GetInputModifier(state);
+
+            var initSegmentName = "stream$RepresentationID$-init.m4s";
+            var segmentName = "stream$RepresentationID$-$Number%05d$.m4s";
+
+            var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f dash -init_seg_name \"{6}\" -media_seg_name \"{7}\" -use_template 0 -use_timeline 1 -min_seg_duration {8} -y \"{9}\"",
+                inputModifier,
+                GetInputArgument(transcodingJobId, state),
+                threads,
+                GetMapArgs(state),
+                GetVideoArguments(state),
+                GetAudioArguments(state),
+                initSegmentName,
+                segmentName,
+                (state.SegmentLength * 1000000).ToString(CultureInfo.InvariantCulture),
+                state.WaitForPath
+                ).Trim();
+
+            return args;
+        }
+
+        protected override int GetStartNumber(StreamState state)
+        {
+            return GetStartNumber(state.VideoRequest);
+        }
+
+        private int GetStartNumber(VideoStreamRequest request)
+        {
+            var segmentId = "0";
+
+            var segmentRequest = request as GetDashSegment;
+            if (segmentRequest != null)
+            {
+                segmentId = segmentRequest.SegmentId;
+            }
+
+            if (string.Equals(segmentId, "init", StringComparison.OrdinalIgnoreCase))
+            {
+                return -1;
+            }
+
+            return int.Parse(segmentId, NumberStyles.Integer, UsCulture);
+        }
+
+        /// <summary>
+        /// Gets the segment file extension.
+        /// </summary>
+        /// <param name="state">The state.</param>
+        /// <returns>System.String.</returns>
+        protected override string GetSegmentFileExtension(StreamState state)
+        {
+            return ".m4s";
+        }
+
+        protected override TranscodingJobType TranscodingJobType
+        {
+            get
+            {
+                return TranscodingJobType.Dash;
+            }
+        }
+
+        private async Task WaitForSegment(string playlist, string segment, CancellationToken cancellationToken)
+        {
+            var tmpPath = playlist + ".tmp";
+
+            var segmentFilename = Path.GetFileName(segment);
+
+            Logger.Debug("Waiting for {0} in {1}", segmentFilename, playlist);
+
+            while (true)
+            {
+                FileStream fileStream;
+                try
+                {
+                    fileStream = FileSystem.GetFileStream(tmpPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
+                }
+                catch (IOException)
+                {
+                    fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
+                }
+                // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
+                using (fileStream)
+                {
+                    using (var reader = new StreamReader(fileStream))
+                    {
+                        while (!reader.EndOfStream)
+                        {
+                            var line = await reader.ReadLineAsync().ConfigureAwait(false);
+
+                            if (line.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
+                            {
+                                Logger.Debug("Finished waiting for {0} in {1}", segmentFilename, playlist);
+                                return;
+                            }
+                        }
+                        await Task.Delay(100, cancellationToken).ConfigureAwait(false);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 2da5c33ce8..8541a60ef5 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -1,7 +1,7 @@
 using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
@@ -23,7 +23,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public abstract class BaseHlsService : BaseStreamingService
     {
-        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
+        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient)
         {
         }
 
@@ -181,7 +181,7 @@ namespace MediaBrowser.Api.Playback.Hls
             return builder.ToString();
         }
 
-        protected async Task WaitForMinimumSegmentCount(string playlist, int segmentCount, CancellationToken cancellationToken)
+        protected virtual async Task WaitForMinimumSegmentCount(string playlist, int segmentCount, CancellationToken cancellationToken)
         {
             Logger.Debug("Waiting for {0} segments in {1}", segmentCount, playlist);
 
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index e639dbdfe3..43a9db1312 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -1,9 +1,8 @@
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Model.Extensions;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
@@ -11,6 +10,7 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
 using ServiceStack;
 using System;
@@ -63,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
     public class DynamicHlsService : BaseHlsService
     {
-        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
+        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient)
         {
             NetworkManager = networkManager;
         }
@@ -100,13 +100,13 @@ namespace MediaBrowser.Api.Playback.Hls
             var cancellationTokenSource = new CancellationTokenSource();
             var cancellationToken = cancellationTokenSource.Token;
 
-            var index = int.Parse(segmentId, NumberStyles.Integer, UsCulture);
+            var requestedIndex = int.Parse(segmentId, NumberStyles.Integer, UsCulture);
 
             var state = await GetState(request, cancellationToken).ConfigureAwait(false);
 
             var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
 
-            var segmentPath = GetSegmentPath(playlistPath, index);
+            var segmentPath = GetSegmentPath(playlistPath, requestedIndex);
             var segmentLength = state.SegmentLength;
 
             var segmentExtension = GetSegmentFileExtension(state);
@@ -115,7 +115,8 @@ namespace MediaBrowser.Api.Playback.Hls
 
             if (File.Exists(segmentPath))
             {
-                return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
+                job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
+                return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
             }
 
             await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
@@ -123,26 +124,26 @@ namespace MediaBrowser.Api.Playback.Hls
             {
                 if (File.Exists(segmentPath))
                 {
-                    return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
+                    job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
+                    return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
                 }
                 else
                 {
                     var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
-
-                    if (currentTranscodingIndex == null || index < currentTranscodingIndex.Value || (index - currentTranscodingIndex.Value) > 4)
+                    var segmentGapRequiringTranscodingChange = 24/state.SegmentLength;
+                    if (currentTranscodingIndex == null || requestedIndex < currentTranscodingIndex.Value || (requestedIndex - currentTranscodingIndex.Value) > segmentGapRequiringTranscodingChange)
                     {
                         // If the playlist doesn't already exist, startup ffmpeg
                         try
                         {
-                            ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType && string.Equals(j.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase));
+                            ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.StreamId ?? request.ClientTime, p => false);
 
                             if (currentTranscodingIndex.HasValue)
                             {
                                 DeleteLastFile(playlistPath, segmentExtension, 0);
                             }
 
-                            var startSeconds = index * state.SegmentLength;
-                            request.StartTimeTicks = TimeSpan.FromSeconds(startSeconds).Ticks;
+                            request.StartTimeTicks = GetSeekPositionTicks(state, requestedIndex);
 
                             job = await StartFfMpeg(state, playlistPath, cancellationTokenSource).ConfigureAwait(false);
                         }
@@ -152,7 +153,7 @@ namespace MediaBrowser.Api.Playback.Hls
                             throw;
                         }
 
-                        await WaitForMinimumSegmentCount(playlistPath, 2, cancellationTokenSource.Token).ConfigureAwait(false);
+                        await WaitForMinimumSegmentCount(playlistPath, 1, cancellationTokenSource.Token).ConfigureAwait(false);
                     }
                 }
             }
@@ -169,11 +170,26 @@ namespace MediaBrowser.Api.Playback.Hls
 
             Logger.Info("returning {0}", segmentPath);
             job = job ?? ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
-            return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
+            return await GetSegmentResult(playlistPath, segmentPath, requestedIndex, segmentLength, job, cancellationToken).ConfigureAwait(false);
+        }
+
+        private long GetSeekPositionTicks(StreamState state, int requestedIndex)
+        {
+            var startSeconds = requestedIndex * state.SegmentLength;
+            var position = TimeSpan.FromSeconds(startSeconds).Ticks;
+
+            return position;
         }
 
         public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
         {
+            var job = ApiEntryPoint.Instance.GetTranscodingJob(playlist, TranscodingJobType);
+
+            if (job == null || job.HasExited)
+            {
+                return null;
+            }
+
             var file = GetLastTranscodingFile(playlist, segmentExtension, FileSystem);
 
             if (file == null)
@@ -204,7 +220,7 @@ namespace MediaBrowser.Api.Playback.Hls
             {
                 return;
             }
-            
+
             try
             {
                 FileSystem.DeleteFile(file.FullName);
@@ -277,7 +293,7 @@ namespace MediaBrowser.Api.Playback.Hls
             CancellationToken cancellationToken)
         {
             // If all transcoding has completed, just return immediately
-            if (!IsTranscoding(playlistPath))
+            if (transcodingJob != null && transcodingJob.HasExited)
             {
                 return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
             }
@@ -288,12 +304,15 @@ namespace MediaBrowser.Api.Playback.Hls
             {
                 using (var reader = new StreamReader(fileStream))
                 {
-                    var text = await reader.ReadToEndAsync().ConfigureAwait(false);
-
-                    // If it appears in the playlist, it's done
-                    if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
+                    while (!reader.EndOfStream)
                     {
-                        return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
+                        var text = await reader.ReadLineAsync().ConfigureAwait(false);
+
+                        // If it appears in the playlist, it's done
+                        if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
+                        {
+                            return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
+                        }
                     }
                 }
             }
@@ -356,13 +375,6 @@ namespace MediaBrowser.Api.Playback.Hls
             });
         }
 
-        private bool IsTranscoding(string playlistPath)
-        {
-            var job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
-
-            return job != null && !job.HasExited;
-        }
-
         private async Task<object> GetAsync(GetMasterHlsVideoStream request, string method)
         {
             var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
@@ -681,20 +693,36 @@ namespace MediaBrowser.Api.Playback.Hls
             // If isEncoding is true we're actually starting ffmpeg
             var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
 
-            var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
-                inputModifier,
-                GetInputArgument(transcodingJobId, state),
-                threads,
-                GetMapArgs(state),
-                GetVideoArguments(state),
-                GetAudioArguments(state),
-                state.SegmentLength.ToString(UsCulture),
-                startNumberParam,
-                state.HlsListSize.ToString(UsCulture),
-                outputPath
-                ).Trim();
-
-            return args;
+            if (state.EnableGenericHlsSegmenter)
+            {
+                var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d.ts";
+
+                return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
+                    inputModifier,
+                    GetInputArgument(transcodingJobId, state),
+                    threads,
+                    GetMapArgs(state),
+                    GetVideoArguments(state),
+                    GetAudioArguments(state),
+                    state.SegmentLength.ToString(UsCulture),
+                    startNumberParam,
+                    outputPath,
+                    outputTsArg
+                    ).Trim();
+            }
+
+            return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
+                            inputModifier,
+                            GetInputArgument(transcodingJobId, state),
+                            threads,
+                            GetMapArgs(state),
+                            GetVideoArguments(state),
+                            GetAudioArguments(state),
+                            state.SegmentLength.ToString(UsCulture),
+                            startNumberParam,
+                            state.HlsListSize.ToString(UsCulture),
+                            outputPath
+                            ).Trim();
         }
 
         /// <summary>
diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
index 9f80fcd0ad..da4ffb55dc 100644
--- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
+++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs
@@ -47,6 +47,9 @@ namespace MediaBrowser.Api.Playback.Hls
     {
         [ApiMember(Name = "DeviceId", Description = "The device id of the client requesting. Used to stop encoding processes when needed.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
         public string DeviceId { get; set; }
+
+        [ApiMember(Name = "StreamId", Description = "The stream id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "DELETE")]
+        public string StreamId { get; set; }
     }
 
     public class HlsSegmentService : BaseApiService
@@ -69,7 +72,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
         public void Delete(StopEncodingProcess request)
         {
-            ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, path => true);
+            ApiEntryPoint.Instance.KillTranscodingJobs(request.DeviceId, request.StreamId, path => true);
         }
 
         /// <summary>
diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
deleted file mode 100644
index 80451c0cc8..0000000000
--- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
+++ /dev/null
@@ -1,675 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.IO;
-using ServiceStack;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Security;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
-
-namespace MediaBrowser.Api.Playback.Hls
-{
-    /// <summary>
-    /// Options is needed for chromecast. Threw Head in there since it's related
-    /// </summary>
-    [Route("/Videos/{Id}/master.mpd", "GET", Summary = "Gets a video stream using Mpeg dash.")]
-    [Route("/Videos/{Id}/master.mpd", "HEAD", Summary = "Gets a video stream using Mpeg dash.")]
-    public class GetMasterManifest : VideoStreamRequest
-    {
-        public bool EnableAdaptiveBitrateStreaming { get; set; }
-
-        public GetMasterManifest()
-        {
-            EnableAdaptiveBitrateStreaming = true;
-        }
-    }
-
-    [Route("/Videos/{Id}/dash/{SegmentId}.ts", "GET")]
-    [Route("/Videos/{Id}/dash/{SegmentId}.mp4", "GET")]
-    public class GetDashSegment : VideoStreamRequest
-    {
-        /// <summary>
-        /// Gets or sets the segment id.
-        /// </summary>
-        /// <value>The segment id.</value>
-        public string SegmentId { get; set; }
-    }
-
-    public class MpegDashService : BaseHlsService
-    {
-        public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
-        {
-            NetworkManager = networkManager;
-        }
-
-        protected INetworkManager NetworkManager { get; private set; }
-
-        public object Get(GetMasterManifest request)
-        {
-            var result = GetAsync(request, "GET").Result;
-
-            return result;
-        }
-
-        public object Head(GetMasterManifest request)
-        {
-            var result = GetAsync(request, "HEAD").Result;
-
-            return result;
-        }
-
-        private async Task<object> GetAsync(GetMasterManifest request, string method)
-        {
-            if (string.Equals(request.AudioCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            {
-                throw new ArgumentException("Audio codec copy is not allowed here.");
-            }
-
-            if (string.Equals(request.VideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            {
-                throw new ArgumentException("Video codec copy is not allowed here.");
-            }
-
-            if (string.IsNullOrEmpty(request.MediaSourceId))
-            {
-                throw new ArgumentException("MediaSourceId is required");
-            }
-
-            var state = await GetState(request, CancellationToken.None).ConfigureAwait(false);
-
-            var playlistText = string.Empty;
-
-            if (string.Equals(method, "GET", StringComparison.OrdinalIgnoreCase))
-            {
-                playlistText = GetManifestText(state);
-            }
-
-            return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.mpd"), new Dictionary<string, string>());
-        }
-
-        private string GetManifestText(StreamState state)
-        {
-            var builder = new StringBuilder();
-
-            var time = TimeSpan.FromTicks(state.RunTimeTicks.Value);
-
-            var duration = "PT" + time.Hours.ToString("00", UsCulture) + "H" + time.Minutes.ToString("00", UsCulture) + "M" + time.Seconds.ToString("00", UsCulture) + ".00S";
-
-            builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
-
-            var profile = string.Equals(GetSegmentFileExtension(state), ".ts", StringComparison.OrdinalIgnoreCase)
-                ? "urn:mpeg:dash:profile:mp2t-simple:2011"
-                : "urn:mpeg:dash:profile:mp2t-simple:2011";
-
-            builder.AppendFormat(
-                "<MPD xmlns=\"urn:mpeg:dash:schema:mpd:2011\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd\" minBufferTime=\"PT2.00S\" mediaPresentationDuration=\"{0}\" maxSegmentDuration=\"PT{1}S\" type=\"static\" profiles=\""+profile+"\">",
-                duration,
-                state.SegmentLength.ToString(CultureInfo.InvariantCulture));
-
-            builder.Append("<ProgramInformation moreInformationURL=\"http://gpac.sourceforge.net\">");
-            builder.Append("</ProgramInformation>");
-
-            builder.AppendFormat("<Period start=\"PT0S\" duration=\"{0}\">", duration);
-            builder.Append("<AdaptationSet segmentAlignment=\"true\">");
-
-            builder.Append("<ContentComponent id=\"1\" contentType=\"video\"/>");
-
-            var lang = state.AudioStream != null ? state.AudioStream.Language : null;
-            if (string.IsNullOrWhiteSpace(lang)) lang = "und";
-
-            builder.AppendFormat("<ContentComponent id=\"2\" contentType=\"audio\" lang=\"{0}\"/>", lang);
-
-            builder.Append(GetRepresentationOpenElement(state, lang));
-
-            AppendSegmentList(state, builder);
-
-            builder.Append("</Representation>");
-            builder.Append("</AdaptationSet>");
-            builder.Append("</Period>");
-
-            builder.Append("</MPD>");
-
-            return builder.ToString();
-        }
-
-        private string GetRepresentationOpenElement(StreamState state, string language)
-        {
-            var codecs = GetVideoCodecDescriptor(state) + "," + GetAudioCodecDescriptor(state);
-
-            var mime = string.Equals(GetSegmentFileExtension(state), ".ts", StringComparison.OrdinalIgnoreCase)
-                ? "video/mp2t"
-                : "video/mp4";
-
-            var xml = "<Representation id=\"1\" mimeType=\"" + mime + "\" startWithSAP=\"1\" codecs=\"" + codecs + "\"";
-
-            if (state.OutputWidth.HasValue)
-            {
-                xml += " width=\"" + state.OutputWidth.Value.ToString(UsCulture) + "\"";
-            }
-            if (state.OutputHeight.HasValue)
-            {
-                xml += " height=\"" + state.OutputHeight.Value.ToString(UsCulture) + "\"";
-            }
-            if (state.OutputAudioSampleRate.HasValue)
-            {
-                xml += " sampleRate=\"" + state.OutputAudioSampleRate.Value.ToString(UsCulture) + "\"";
-            }
-
-            if (state.TotalOutputBitrate.HasValue)
-            {
-                xml += " bandwidth=\"" + state.TotalOutputBitrate.Value.ToString(UsCulture) + "\"";
-            }
-
-            xml += ">";
-
-            return xml;
-        }
-
-        private string GetVideoCodecDescriptor(StreamState state)
-        {
-            // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
-            // http://www.chipwreck.de/blog/2010/02/25/html-5-video-tag-and-attributes/
-
-            var level = state.TargetVideoLevel ?? 0;
-            var profile = state.TargetVideoProfile ?? string.Empty;
-
-            if (profile.IndexOf("high", StringComparison.OrdinalIgnoreCase) != -1)
-            {
-                if (level >= 4.1)
-                {
-                    return "avc1.640028";
-                }
-
-                if (level >= 4)
-                {
-                    return "avc1.640028";
-                }
-
-                return "avc1.64001f";
-            }
-
-            if (profile.IndexOf("main", StringComparison.OrdinalIgnoreCase) != -1)
-            {
-                if (level >= 4)
-                {
-                    return "avc1.4d0028";
-                }
-
-                if (level >= 3.1)
-                {
-                    return "avc1.4d001f";
-                }
-
-                return "avc1.4d001e";
-            }
-
-            if (level >= 3.1)
-            {
-                return "avc1.42001f";
-            }
-
-            return "avc1.42E01E";
-        }
-
-        private string GetAudioCodecDescriptor(StreamState state)
-        {
-            // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
-
-            if (string.Equals(state.OutputAudioCodec, "mp3", StringComparison.OrdinalIgnoreCase))
-            {
-                return "mp4a.40.34";
-            }
-
-            // AAC 5ch
-            if (state.OutputAudioChannels.HasValue && state.OutputAudioChannels.Value >= 5)
-            {
-                return "mp4a.40.5";
-            }
-
-            // AAC 2ch
-            return "mp4a.40.2";
-        }
-
-        public object Get(GetDashSegment request)
-        {
-            return GetDynamicSegment(request, request.SegmentId).Result;
-        }
-
-        private void AppendSegmentList(StreamState state, StringBuilder builder)
-        {
-            var extension = GetSegmentFileExtension(state);
-
-            var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
-
-            var queryStringIndex = Request.RawUrl.IndexOf('?');
-            var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
-
-            var index = 0;
-            builder.Append("<SegmentList timescale=\"1000\" duration=\"10000\">");
-
-
-            while (seconds > 0)
-            {
-                var segmentUrl = string.Format("dash/{0}{1}{2}",
-                    index.ToString(UsCulture),
-                    extension,
-                    SecurityElement.Escape(queryString));
-
-                if (index == 0)
-                {
-                    builder.AppendFormat("<Initialization sourceURL=\"{0}\"/>", segmentUrl);
-                }
-                else
-                {
-                    builder.AppendFormat("<SegmentURL media=\"{0}\"/>", segmentUrl);
-                }
-
-                seconds -= state.SegmentLength;
-                index++;
-            }
-            builder.Append("</SegmentList>");
-        }
-
-        private async Task<object> GetDynamicSegment(VideoStreamRequest request, string segmentId)
-        {
-            if ((request.StartTimeTicks ?? 0) > 0)
-            {
-                throw new ArgumentException("StartTimeTicks is not allowed.");
-            }
-
-            var cancellationTokenSource = new CancellationTokenSource();
-            var cancellationToken = cancellationTokenSource.Token;
-
-            var index = int.Parse(segmentId, NumberStyles.Integer, UsCulture);
-
-            var state = await GetState(request, cancellationToken).ConfigureAwait(false);
-
-            var playlistPath = Path.ChangeExtension(state.OutputFilePath, ".m3u8");
-
-            var segmentExtension = GetSegmentFileExtension(state);
-
-            var segmentPath = GetSegmentPath(playlistPath, segmentExtension, index);
-            var segmentLength = state.SegmentLength;
-
-            TranscodingJob job = null;
-
-            if (File.Exists(segmentPath))
-            {
-                return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
-            }
-
-            await ApiEntryPoint.Instance.TranscodingStartLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
-            try
-            {
-                if (File.Exists(segmentPath))
-                {
-                    return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
-                }
-                else
-                {
-                    var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath, segmentExtension);
-
-                    if (currentTranscodingIndex == null || index < currentTranscodingIndex.Value || (index - currentTranscodingIndex.Value) > 4)
-                    {
-                        // If the playlist doesn't already exist, startup ffmpeg
-                        try
-                        {
-                            ApiEntryPoint.Instance.KillTranscodingJobs(j => j.Type == TranscodingJobType && string.Equals(j.DeviceId, request.DeviceId, StringComparison.OrdinalIgnoreCase), p => !string.Equals(p, playlistPath, StringComparison.OrdinalIgnoreCase));
-
-                            if (currentTranscodingIndex.HasValue)
-                            {
-                                DeleteLastFile(playlistPath, segmentExtension, 0);
-                            }
-
-                            var startSeconds = index * state.SegmentLength;
-                            request.StartTimeTicks = TimeSpan.FromSeconds(startSeconds).Ticks;
-
-                            job = await StartFfMpeg(state, playlistPath, cancellationTokenSource, Path.GetDirectoryName(playlistPath)).ConfigureAwait(false);
-                        }
-                        catch
-                        {
-                            state.Dispose();
-                            throw;
-                        }
-
-                        await WaitForMinimumSegmentCount(playlistPath, 2, cancellationTokenSource.Token).ConfigureAwait(false);
-                    }
-                }
-            }
-            finally
-            {
-                ApiEntryPoint.Instance.TranscodingStartLock.Release();
-            }
-
-            Logger.Info("waiting for {0}", segmentPath);
-            while (!File.Exists(segmentPath))
-            {
-                await Task.Delay(50, cancellationToken).ConfigureAwait(false);
-            }
-
-            Logger.Info("returning {0}", segmentPath);
-            job = job ?? ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
-            return await GetSegmentResult(playlistPath, segmentPath, index, segmentLength, job, cancellationToken).ConfigureAwait(false);
-        }
-
-        private async Task<object> GetSegmentResult(string playlistPath,
-            string segmentPath,
-            int segmentIndex,
-            int segmentLength,
-            TranscodingJob transcodingJob,
-            CancellationToken cancellationToken)
-        {
-            // If all transcoding has completed, just return immediately
-            if (!IsTranscoding(playlistPath))
-            {
-                return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
-            }
-
-            var segmentFilename = Path.GetFileName(segmentPath);
-
-            using (var fileStream = FileSystem.GetFileStream(playlistPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
-            {
-                using (var reader = new StreamReader(fileStream))
-                {
-                    var text = await reader.ReadToEndAsync().ConfigureAwait(false);
-
-                    // If it appears in the playlist, it's done
-                    if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1)
-                    {
-                        return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
-                    }
-                }
-            }
-
-            // if a different file is encoding, it's done
-            //var currentTranscodingIndex = GetCurrentTranscodingIndex(playlistPath);
-            //if (currentTranscodingIndex > segmentIndex)
-            //{
-            //return GetSegmentResult(segmentPath, segmentIndex);
-            //}
-
-            // Wait for the file to stop being written to, then stream it
-            var length = new FileInfo(segmentPath).Length;
-            var eofCount = 0;
-
-            while (eofCount < 10)
-            {
-                var info = new FileInfo(segmentPath);
-
-                if (!info.Exists)
-                {
-                    break;
-                }
-
-                var newLength = info.Length;
-
-                if (newLength == length)
-                {
-                    eofCount++;
-                }
-                else
-                {
-                    eofCount = 0;
-                }
-
-                length = newLength;
-                await Task.Delay(100, cancellationToken).ConfigureAwait(false);
-            }
-
-            return GetSegmentResult(segmentPath, segmentIndex, segmentLength, transcodingJob);
-        }
-
-        private object GetSegmentResult(string segmentPath, int index, int segmentLength, TranscodingJob transcodingJob)
-        {
-            var segmentEndingSeconds = (1 + index) * segmentLength;
-            var segmentEndingPositionTicks = TimeSpan.FromSeconds(segmentEndingSeconds).Ticks;
-
-            return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
-            {
-                Path = segmentPath,
-                FileShare = FileShare.ReadWrite,
-                OnComplete = () =>
-                {
-                    if (transcodingJob != null)
-                    {
-                        transcodingJob.DownloadPositionTicks = Math.Max(transcodingJob.DownloadPositionTicks ?? segmentEndingPositionTicks, segmentEndingPositionTicks);
-                    }
-
-                }
-            });
-        }
-
-        private bool IsTranscoding(string playlistPath)
-        {
-            var job = ApiEntryPoint.Instance.GetTranscodingJob(playlistPath, TranscodingJobType);
-
-            return job != null && !job.HasExited;
-        }
-        
-        public int? GetCurrentTranscodingIndex(string playlist, string segmentExtension)
-        {
-            var file = GetLastTranscodingFile(playlist, segmentExtension, FileSystem);
-
-            if (file == null)
-            {
-                return null;
-            }
-
-            var playlistFilename = Path.GetFileNameWithoutExtension(playlist);
-
-            var indexString = Path.GetFileNameWithoutExtension(file.Name).Substring(playlistFilename.Length);
-
-            return int.Parse(indexString, NumberStyles.Integer, UsCulture);
-        }
-
-        private void DeleteLastFile(string path, string segmentExtension, int retryCount)
-        {
-            if (retryCount >= 5)
-            {
-                return;
-            }
-
-            var file = GetLastTranscodingFile(path, segmentExtension, FileSystem);
-
-            if (file != null)
-            {
-                try
-                {
-                    FileSystem.DeleteFile(file.FullName);
-                }
-                catch (IOException ex)
-                {
-                    Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, file.FullName);
-
-                    Thread.Sleep(100);
-                    DeleteLastFile(path, segmentExtension, retryCount + 1);
-                }
-                catch (Exception ex)
-                {
-                    Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, file.FullName);
-                }
-            }
-        }
-
-        private static FileInfo GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem)
-        {
-            var folder = Path.GetDirectoryName(playlist);
-
-            try
-            {
-                return new DirectoryInfo(folder)
-                    .EnumerateFiles("*", SearchOption.TopDirectoryOnly)
-                    .Where(i => string.Equals(i.Extension, segmentExtension, StringComparison.OrdinalIgnoreCase))
-                    .OrderByDescending(fileSystem.GetLastWriteTimeUtc)
-                    .FirstOrDefault();
-            }
-            catch (DirectoryNotFoundException)
-            {
-                return null;
-            }
-        }
-
-        protected override int GetStartNumber(StreamState state)
-        {
-            return GetStartNumber(state.VideoRequest);
-        }
-
-        private int GetStartNumber(VideoStreamRequest request)
-        {
-            var segmentId = "0";
-
-            var segmentRequest = request as GetDynamicHlsVideoSegment;
-            if (segmentRequest != null)
-            {
-                segmentId = segmentRequest.SegmentId;
-            }
-
-            return int.Parse(segmentId, NumberStyles.Integer, UsCulture);
-        }
-
-        private string GetSegmentPath(string playlist, string segmentExtension, int index)
-        {
-            var folder = Path.GetDirectoryName(playlist);
-
-            var filename = Path.GetFileNameWithoutExtension(playlist);
-
-            return Path.Combine(folder, filename + index.ToString("000", UsCulture) + segmentExtension);
-        }
-        
-        protected override string GetAudioArguments(StreamState state)
-        {
-            var codec = state.OutputAudioCodec;
-
-            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
-            {
-                return "-codec:a:0 copy";
-            }
-
-            var args = "-codec:a:0 " + codec;
-
-            var channels = state.OutputAudioChannels;
-
-            if (channels.HasValue)
-            {
-                args += " -ac " + channels.Value;
-            }
-
-            var bitrate = state.OutputAudioBitrate;
-
-            if (bitrate.HasValue)
-            {
-                args += " -ab " + bitrate.Value.ToString(UsCulture);
-            }
-
-            args += " " + GetAudioFilterParam(state, true);
-
-            return args;
-        }
-
-        protected override string GetVideoArguments(StreamState state)
-        {
-            var codec = state.OutputVideoCodec;
-
-            var args = "-codec:v:0 " + codec;
-
-            if (state.EnableMpegtsM2TsMode)
-            {
-                args += " -mpegts_m2ts_mode 1";
-            }
-
-            // See if we can save come cpu cycles by avoiding encoding
-            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
-            {
-                return state.VideoStream != null && IsH264(state.VideoStream) ?
-                    args + " -bsf:v h264_mp4toannexb" :
-                    args;
-            }
-
-            var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
-                state.SegmentLength.ToString(UsCulture));
-
-            var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream;
-
-            args+= " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg;
-
-            args += " -r 24 -g 24";
-
-            // Add resolution params, if specified
-            if (!hasGraphicalSubs)
-            {
-                args += GetOutputSizeParam(state, codec, false);
-            }
-
-            // This is for internal graphical subs
-            if (hasGraphicalSubs)
-            {
-                args += GetGraphicalSubtitleParam(state, codec);
-            }
-
-            return args;
-        }
-
-        protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
-        {
-            // test url http://192.168.1.2:8096/videos/233e8905d559a8f230db9bffd2ac9d6d/master.mpd?mediasourceid=233e8905d559a8f230db9bffd2ac9d6d&videocodec=h264&audiocodec=aac&maxwidth=1280&videobitrate=500000&audiobitrate=128000&profile=baseline&level=3
-            // Good info on i-frames http://blog.streamroot.io/encode-multi-bitrate-videos-mpeg-dash-mse-based-media-players/
-
-            var threads = GetNumberOfThreads(state, false);
-
-            var inputModifier = GetInputModifier(state);
-
-            // If isEncoding is true we're actually starting ffmpeg
-            var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0";
-
-            var segmentFilename = Path.GetFileNameWithoutExtension(outputPath) + "%03d" + GetSegmentFileExtension(state);
-
-            var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}",
-                inputModifier,
-                GetInputArgument(transcodingJobId, state),
-                threads,
-                GetMapArgs(state),
-                GetVideoArguments(state),
-                GetAudioArguments(state),
-                state.SegmentLength.ToString(UsCulture),
-                startNumberParam,
-                state.HlsListSize.ToString(UsCulture),
-                outputPath,
-                segmentFilename
-                ).Trim();
-
-            return args;
-        }
-
-        /// <summary>
-        /// Gets the segment file extension.
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <returns>System.String.</returns>
-        protected override string GetSegmentFileExtension(StreamState state)
-        {
-            return ".mp4";
-        }
-
-        protected override TranscodingJobType TranscodingJobType
-        {
-            get
-            {
-                return TranscodingJobType.Dash;
-            }
-        }
-    }
-}
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 8de52ea028..533764f64a 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -1,7 +1,7 @@
 using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
@@ -57,7 +57,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public class VideoHlsService : BaseHlsService
     {
-        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
+        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient)
         {
         }
 
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index 77178c8cc1..943d9fe481 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -1,7 +1,7 @@
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Entities;
+using System;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.MediaInfo;
 using ServiceStack;
@@ -22,51 +22,54 @@ namespace MediaBrowser.Api.Playback
         public string UserId { get; set; }
     }
 
+    [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
+    public class GetPlaybackInfo : IReturn<LiveMediaInfoResult>
+    {
+        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+
+        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string UserId { get; set; }
+    }
+
     [Authenticated]
     public class MediaInfoService : BaseApiService
     {
-        private readonly ILibraryManager _libraryManager;
-        private readonly IChannelManager _channelManager;
-        private readonly IUserManager _userManager;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
-        public MediaInfoService(ILibraryManager libraryManager, IChannelManager channelManager, IUserManager userManager)
+        public MediaInfoService(IMediaSourceManager mediaSourceManager)
         {
-            _libraryManager = libraryManager;
-            _channelManager = channelManager;
-            _userManager = userManager;
+            _mediaSourceManager = mediaSourceManager;
         }
 
-        public async Task<object> Get(GetLiveMediaInfo request)
+        public Task<object> Get(GetPlaybackInfo request)
         {
-            var item = _libraryManager.GetItemById(request.Id);
-            IEnumerable<MediaSourceInfo> mediaSources;
+            return GetPlaybackInfo(request.Id, request.UserId);
+        }
 
-            var channelItem = item as IChannelMediaItem;
-            var user = _userManager.GetUserById(request.UserId);
+        public Task<object> Get(GetLiveMediaInfo request)
+        {
+            return GetPlaybackInfo(request.Id, request.UserId);
+        }
 
-            if (channelItem != null)
+        private async Task<object> GetPlaybackInfo(string id, string userId)
+        {
+            IEnumerable<MediaSourceInfo> mediaSources;
+            var result = new LiveMediaInfoResult();
+
+            try
             {
-                mediaSources = await _channelManager.GetChannelItemMediaSources(request.Id, true, CancellationToken.None)
-                        .ConfigureAwait(false);
+                mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
             }
-            else
+            catch (PlaybackException ex)
             {
-                var hasMediaSources = (IHasMediaSources)item;
-
-                if (user == null)
-                {
-                    mediaSources = hasMediaSources.GetMediaSources(true);
-                }
-                else
-                {
-                    mediaSources = hasMediaSources.GetMediaSources(true, user);
-                }
+                mediaSources = new List<MediaSourceInfo>();
+                result.ErrorCode = ex.ErrorCode;
             }
 
-            return ToOptimizedResult(new LiveMediaInfoResult
-            {
-                MediaSources = mediaSources.ToList()
-            });
+            result.MediaSources = mediaSources.ToList();
+
+            return ToOptimizedResult(result);
         }
     }
 }
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index 37155b8f94..f3193c9548 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -1,8 +1,8 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
@@ -32,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class AudioService : BaseProgressiveStreamingService
     {
-        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager, imageProcessor, httpClient)
+        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
         {
         }
 
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 9dbe3389e6..baf6ab653a 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -1,8 +1,8 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
@@ -15,7 +15,6 @@ using ServiceStack.Web;
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -29,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
         protected readonly IImageProcessor ImageProcessor;
         protected readonly IHttpClient HttpClient;
 
-        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager)
+        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient)
         {
             ImageProcessor = imageProcessor;
             HttpClient = httpClient;
@@ -153,49 +152,12 @@ namespace MediaBrowser.Api.Playback.Progressive
 
                 using (state)
                 {
-                    var job = string.IsNullOrEmpty(request.TranscodingJobId) ?
-                        null :
-                        ApiEntryPoint.Instance.GetTranscodingJob(request.TranscodingJobId);
-
-                    var limits = new List<long>();
-                    if (state.InputBitrate.HasValue)
-                    {
-                        // Bytes per second
-                        limits.Add((state.InputBitrate.Value / 8));
-                    }
-                    if (state.InputFileSize.HasValue && state.RunTimeTicks.HasValue)
-                    {
-                        var totalSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds;
-
-                        if (totalSeconds > 1)
-                        {
-                            var timeBasedLimit = state.InputFileSize.Value / totalSeconds;
-                            limits.Add(Convert.ToInt64(timeBasedLimit));
-                        }
-                    }
-
-                    // Take the greater of the above to methods, just to be safe
-                    var throttleLimit = limits.Count > 0 ? limits.First() : 0;
-
-                    // Pad to play it safe
-                    var bytesPerSecond = Convert.ToInt64(1.05 * throttleLimit);
-
-                    // Don't even start evaluating this until at least two minutes have content have been consumed
-                    var targetGap = throttleLimit * 120;
-
                     return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
                     {
                         ResponseHeaders = responseHeaders,
                         ContentType = contentType,
                         IsHeadRequest = isHeadRequest,
-                        Path = state.MediaPath,
-                        Throttle = request.Throttle,
-
-                        ThrottleLimit = bytesPerSecond,
-
-                        MinThrottlePosition = targetGap,
-
-                        ThrottleCallback = (l1, l2) => ThrottleCallack(l1, l2, bytesPerSecond, job)
+                        Path = state.MediaPath
                     });
                 }
             }
@@ -234,67 +196,6 @@ namespace MediaBrowser.Api.Playback.Progressive
             }
         }
 
-        private readonly long _gapLengthInTicks = TimeSpan.FromMinutes(3).Ticks;
-
-        private long ThrottleCallack(long currentBytesPerSecond, long bytesWritten, long originalBytesPerSecond, TranscodingJob job)
-        {
-            var bytesDownloaded = job.BytesDownloaded ?? 0;
-            var transcodingPositionTicks = job.TranscodingPositionTicks ?? 0;
-            var downloadPositionTicks = job.DownloadPositionTicks ?? 0;
-
-            var path = job.Path;
-
-            if (bytesDownloaded > 0 && transcodingPositionTicks > 0)
-            {
-                // Progressive Streaming - byte-based consideration
-
-                try
-                {
-                    var bytesTranscoded = job.BytesTranscoded ?? new FileInfo(path).Length;
-
-                    // Estimate the bytes the transcoder should be ahead
-                    double gapFactor = _gapLengthInTicks;
-                    gapFactor /= transcodingPositionTicks;
-                    var targetGap = bytesTranscoded * gapFactor;
-
-                    var gap = bytesTranscoded - bytesDownloaded;
-
-                    if (gap < targetGap)
-                    {
-                        //Logger.Debug("Not throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
-                        return 0;
-                    }
-
-                    //Logger.Debug("Throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
-                }
-                catch
-                {
-                    //Logger.Error("Error getting output size");
-                }
-            }
-            else if (downloadPositionTicks > 0 && transcodingPositionTicks > 0)
-            {
-                // HLS - time-based consideration
-
-                var targetGap = _gapLengthInTicks;
-                var gap = transcodingPositionTicks - downloadPositionTicks;
-
-                if (gap < targetGap)
-                {
-                    //Logger.Debug("Not throttling transcoder gap {0} target gap {1}", gap, targetGap);
-                    return 0;
-                }
-
-                //Logger.Debug("Throttling transcoder gap {0} target gap {1}", gap, targetGap);
-            }
-            else
-            {
-                //Logger.Debug("No throttle data for " + path);
-            }
-
-            return originalBytesPerSecond;
-        }
-
         /// <summary>
         /// Gets the static remote stream result.
         /// </summary>
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index 7e86b867f6..e7b90c820f 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -1,8 +1,8 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
@@ -63,7 +63,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class VideoService : BaseProgressiveStreamingService
     {
-        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder, deviceManager, imageProcessor, httpClient)
+        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IProcessManager processManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, processManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
         {
         }
 
diff --git a/MediaBrowser.Api/Playback/StreamRequest.cs b/MediaBrowser.Api/Playback/StreamRequest.cs
index dc22fc7548..b52260b506 100644
--- a/MediaBrowser.Api/Playback/StreamRequest.cs
+++ b/MediaBrowser.Api/Playback/StreamRequest.cs
@@ -71,8 +71,8 @@ namespace MediaBrowser.Api.Playback
 
         public string Params { get; set; }
         public string ClientTime { get; set; }
+        public string StreamId { get; set; }
 
-        public bool Throttle { get; set; }
         public string TranscodingJobId { get; set; }
     }
 
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 40e765f1ae..1d4dd1aafb 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -1,17 +1,16 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Net;
 using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Threading;
-using MediaBrowser.Model.Net;
 
 namespace MediaBrowser.Api.Playback
 {
@@ -23,6 +22,7 @@ namespace MediaBrowser.Api.Playback
         public string RequestedUrl { get; set; }
 
         public StreamRequest Request { get; set; }
+        public TranscodingThrottler TranscodingThrottler { get; set; }
 
         public VideoStreamRequest VideoRequest
         {
@@ -52,10 +52,12 @@ namespace MediaBrowser.Api.Playback
         public IIsoMount IsoMount { get; set; }
 
         public string MediaPath { get; set; }
+        public string WaitForPath { get; set; }
 
         public MediaProtocol InputProtocol { get; set; }
 
         public bool IsInputVideo { get; set; }
+        public bool IsInputArchive { get; set; }
 
         public VideoType VideoType { get; set; }
         public IsoType? IsoType { get; set; }
@@ -64,8 +66,8 @@ namespace MediaBrowser.Api.Playback
 
         public string LiveTvStreamId { get; set; }
 
-        public int SegmentLength = 6;
-
+        public int SegmentLength = 3;
+        public bool EnableGenericHlsSegmenter = false;
         public int HlsListSize
         {
             get
@@ -112,6 +114,7 @@ namespace MediaBrowser.Api.Playback
         public long? EncodingDurationTicks { get; set; }
 
         public string ItemType { get; set; }
+        public string ItemId { get; set; }
 
         public string GetMimeType(string outputPath)
         {
@@ -125,6 +128,7 @@ namespace MediaBrowser.Api.Playback
 
         public void Dispose()
         {
+            DisposeTranscodingThrottler();
             DisposeLiveStream();
             DisposeLogStream();
             DisposeIsoMount();
@@ -147,6 +151,23 @@ namespace MediaBrowser.Api.Playback
             }
         }
 
+        private void DisposeTranscodingThrottler()
+        {
+            if (TranscodingThrottler != null)
+            {
+                try
+                {
+                    TranscodingThrottler.Dispose();
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error disposing TranscodingThrottler", ex);
+                }
+
+                TranscodingThrottler = null;
+            }
+        }
+
         private void DisposeIsoMount()
         {
             if (IsoMount != null)
diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
new file mode 100644
index 0000000000..943a4d0652
--- /dev/null
+++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs
@@ -0,0 +1,159 @@
+using MediaBrowser.Controller.Diagnostics;
+using MediaBrowser.Model.Logging;
+using System;
+using System.IO;
+using System.Threading;
+
+namespace MediaBrowser.Api.Playback
+{
+    public class TranscodingThrottler : IDisposable
+    {
+        private readonly TranscodingJob _job;
+        private readonly ILogger _logger;
+        private readonly IProcessManager _processManager;
+        private Timer _timer;
+        private bool _isPaused;
+
+        private readonly long _gapLengthInTicks = TimeSpan.FromMinutes(2).Ticks;
+
+        public TranscodingThrottler(TranscodingJob job, ILogger logger, IProcessManager processManager)
+        {
+            _job = job;
+            _logger = logger;
+            _processManager = processManager;
+        }
+
+        public void Start()
+        {
+            _timer = new Timer(TimerCallback, null, 5000, 5000);
+        }
+
+        private void TimerCallback(object state)
+        {
+            if (_job.HasExited)
+            {
+                DisposeTimer();
+                return;
+            }
+
+            if (IsThrottleAllowed(_job))
+            {
+                PauseTranscoding();
+            }
+            else
+            {
+                UnpauseTranscoding();
+            }
+        }
+
+        private void PauseTranscoding()
+        {
+            if (!_isPaused)
+            {
+                _logger.Debug("Sending pause command to ffmpeg");
+
+                try
+                {
+                    _job.Process.StandardInput.Write("c");
+                    _isPaused = true;
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error pausing transcoding", ex);
+                }
+            }
+        }
+
+        private void UnpauseTranscoding()
+        {
+            if (_isPaused)
+            {
+                _logger.Debug("Sending unpause command to ffmpeg");
+
+                try
+                {
+                    _job.Process.StandardInput.WriteLine();
+                    _isPaused = false;
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error unpausing transcoding", ex);
+                }
+            }
+        }
+
+        private bool IsThrottleAllowed(TranscodingJob job)
+        {
+            var bytesDownloaded = job.BytesDownloaded ?? 0;
+            var transcodingPositionTicks = job.TranscodingPositionTicks ?? 0;
+            var downloadPositionTicks = job.DownloadPositionTicks ?? 0;
+
+            var path = job.Path;
+
+            if (downloadPositionTicks > 0 && transcodingPositionTicks > 0)
+            {
+                // HLS - time-based consideration
+
+                var targetGap = _gapLengthInTicks;
+                var gap = transcodingPositionTicks - downloadPositionTicks;
+
+                if (gap < targetGap)
+                {
+                    //_logger.Debug("Not throttling transcoder gap {0} target gap {1}", gap, targetGap);
+                    return false;
+                }
+
+                //_logger.Debug("Throttling transcoder gap {0} target gap {1}", gap, targetGap);
+                return true;
+            }
+
+            if (bytesDownloaded > 0 && transcodingPositionTicks > 0)
+            {
+                // Progressive Streaming - byte-based consideration
+
+                try
+                {
+                    var bytesTranscoded = job.BytesTranscoded ?? new FileInfo(path).Length;
+
+                    // Estimate the bytes the transcoder should be ahead
+                    double gapFactor = _gapLengthInTicks;
+                    gapFactor /= transcodingPositionTicks;
+                    var targetGap = bytesTranscoded * gapFactor;
+
+                    var gap = bytesTranscoded - bytesDownloaded;
+
+                    if (gap < targetGap)
+                    {
+                        //_logger.Debug("Not throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
+                        return false;
+                    }
+
+                    //_logger.Debug("Throttling transcoder gap {0} target gap {1} bytes downloaded {2}", gap, targetGap, bytesDownloaded);
+                    return true;
+                }
+                catch
+                {
+                    //_logger.Error("Error getting output size");
+                    return false;
+                }
+            }
+
+            //_logger.Debug("No throttle data for " + path);
+            return false;
+        }
+
+        public void Dispose()
+        {
+            DisposeTimer();
+        }
+
+        private void DisposeTimer()
+        {
+            if (_timer != null)
+            {
+                _timer.Dispose();
+                _timer = null;
+            }
+        }
+    }
+}
diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs
index f5c8935f80..4bd78f1f55 100644
--- a/MediaBrowser.Api/PluginService.cs
+++ b/MediaBrowser.Api/PluginService.cs
@@ -5,6 +5,7 @@ using MediaBrowser.Common.Updates;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Registration;
 using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using ServiceStack.Web;
@@ -106,6 +107,14 @@ namespace MediaBrowser.Api
         public string Mb2Equivalent { get; set; }
     }
 
+    [Route("/Registrations/{Name}", "GET", Summary = "Gets registration status for a feature")]
+    [Authenticated]
+    public class GetRegistration : IReturn<RegistrationInfo>
+    {
+        [ApiMember(Name = "Name", Description = "Feature Name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Name { get; set; }
+    }
+
     /// <summary>
     /// Class PluginsService
     /// </summary>
@@ -144,13 +153,26 @@ namespace MediaBrowser.Api
         /// </summary>
         /// <param name="request">The request.</param>
         /// <returns>System.Object.</returns>
-        public object Get(GetRegistrationStatus request)
+        public async Task<object> Get(GetRegistrationStatus request)
         {
-            var result = _securityManager.GetRegistrationStatus(request.Name, request.Mb2Equivalent).Result;
+            var result = await _securityManager.GetRegistrationStatus(request.Name, request.Mb2Equivalent).ConfigureAwait(false);
 
             return ToOptimizedResult(result);
         }
 
+        public async Task<object> Get(GetRegistration request)
+        {
+            var result = await _securityManager.GetRegistrationStatus(request.Name).ConfigureAwait(false);
+
+            return ToOptimizedResult(new RegistrationInfo
+            {
+                ExpirationDate = result.ExpirationDate,
+                IsRegistered = result.IsRegistered,
+                IsTrial = result.TrialVersion,
+                Name = request.Name
+            });
+        }
+
         /// <summary>
         /// Gets the specified request.
         /// </summary>
@@ -178,7 +200,7 @@ namespace MediaBrowser.Api
             }
             catch
             {
-                
+
             }
 
             return ToOptimizedSerializedResultUsingCache(result);
diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
index e3722b4a75..949dac9261 100644
--- a/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
+++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTaskService.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Tasks;
 using ServiceStack;
-using ServiceStack.Text.Controller;
 using System;
 using System.Collections.Generic;
 using System.Linq;
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs
index ee48946d5d..2cca72593b 100644
--- a/MediaBrowser.Api/SearchService.cs
+++ b/MediaBrowser.Api/SearchService.cs
@@ -211,7 +211,7 @@ namespace MediaBrowser.Api
                 result.SongCount = album.Tracks.Count();
 
                 result.Artists = album.Artists.ToArray();
-                result.AlbumArtist = album.AlbumArtists.FirstOrDefault();
+                result.AlbumArtist = album.AlbumArtist;
             }
 
             var song = item as Audio;
diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs
index 319b3d28c6..52ecb95ec6 100644
--- a/MediaBrowser.Api/Session/SessionsService.cs
+++ b/MediaBrowser.Api/Session/SessionsService.cs
@@ -418,7 +418,7 @@ namespace MediaBrowser.Api.Session
                 SeekPositionTicks = request.SeekPositionTicks
             };
 
-            var task = _sessionManager.SendPlaystateCommand(GetSession().Id, request.Id, command, CancellationToken.None);
+            var task = _sessionManager.SendPlaystateCommand(GetSession().Result.Id, request.Id, command, CancellationToken.None);
 
             Task.WaitAll(task);
         }
@@ -436,7 +436,7 @@ namespace MediaBrowser.Api.Session
                 ItemType = request.ItemType
             };
 
-            var task = _sessionManager.SendBrowseCommand(GetSession().Id, request.Id, command, CancellationToken.None);
+            var task = _sessionManager.SendBrowseCommand(GetSession().Result.Id, request.Id, command, CancellationToken.None);
 
             Task.WaitAll(task);
         }
@@ -455,7 +455,7 @@ namespace MediaBrowser.Api.Session
                 name = commandType.ToString();
             }
 
-            var currentSession = GetSession();
+            var currentSession = GetSession().Result;
 
             var command = new GeneralCommand
             {
@@ -481,7 +481,7 @@ namespace MediaBrowser.Api.Session
                 Text = request.Text
             };
 
-            var task = _sessionManager.SendMessageCommand(GetSession().Id, request.Id, command, CancellationToken.None);
+            var task = _sessionManager.SendMessageCommand(GetSession().Result.Id, request.Id, command, CancellationToken.None);
 
             Task.WaitAll(task);
         }
@@ -500,14 +500,14 @@ namespace MediaBrowser.Api.Session
                 StartPositionTicks = request.StartPositionTicks
             };
 
-            var task = _sessionManager.SendPlayCommand(GetSession().Id, request.Id, command, CancellationToken.None);
+            var task = _sessionManager.SendPlayCommand(GetSession().Result.Id, request.Id, command, CancellationToken.None);
 
             Task.WaitAll(task);
         }
 
         public void Post(SendGeneralCommand request)
         {
-            var currentSession = GetSession();
+            var currentSession = GetSession().Result;
 
             var command = new GeneralCommand
             {
@@ -522,7 +522,7 @@ namespace MediaBrowser.Api.Session
 
         public void Post(SendFullGeneralCommand request)
         {
-            var currentSession = GetSession();
+            var currentSession = GetSession().Result;
 
             request.ControllingUserId = currentSession.UserId.HasValue ? currentSession.UserId.Value.ToString("N") : null;
 
@@ -545,7 +545,7 @@ namespace MediaBrowser.Api.Session
         {
             if (string.IsNullOrWhiteSpace(request.Id))
             {
-                request.Id = GetSession().Id;
+                request.Id = GetSession().Result.Id;
             }
             _sessionManager.ReportCapabilities(request.Id, new ClientCapabilities
             {
@@ -569,7 +569,7 @@ namespace MediaBrowser.Api.Session
         {
             if (string.IsNullOrWhiteSpace(request.Id))
             {
-                request.Id = GetSession().Id;
+                request.Id = GetSession().Result.Id;
             }
             _sessionManager.ReportCapabilities(request.Id, request);
         }
diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs
index bf5c04540b..4655f2c6f9 100644
--- a/MediaBrowser.Api/StartupWizardService.cs
+++ b/MediaBrowser.Api/StartupWizardService.cs
@@ -65,6 +65,7 @@ namespace MediaBrowser.Api
             _config.Configuration.MergeMetadataAndImagesByName = true;
             _config.Configuration.EnableStandaloneMetadata = true;
             _config.Configuration.EnableLibraryMetadataSubFolder = true;
+            _config.Configuration.EnableUserSpecificUserViews = true;
             _config.SaveConfiguration();
         }
 
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 32e6ba076d..07eb74e81b 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -124,20 +124,23 @@ namespace MediaBrowser.Api.Subtitles
         private readonly ILibraryManager _libraryManager;
         private readonly ISubtitleManager _subtitleManager;
         private readonly ISubtitleEncoder _subtitleEncoder;
+        private readonly IMediaSourceManager _mediaSourceManager;
+        private readonly IProviderManager _providerManager;
 
-        public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder)
+        public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProviderManager providerManager)
         {
             _libraryManager = libraryManager;
             _subtitleManager = subtitleManager;
             _subtitleEncoder = subtitleEncoder;
+            _mediaSourceManager = mediaSourceManager;
+            _providerManager = providerManager;
         }
 
         public object Get(GetSubtitlePlaylist request)
         {
             var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
 
-            var mediaSource = item.GetMediaSources(false)
-                .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id));
+            var mediaSource = _mediaSourceManager.GetStaticMediaSource(item, request.MediaSourceId, false);
 
             var builder = new StringBuilder();
 
@@ -255,7 +258,7 @@ namespace MediaBrowser.Api.Subtitles
                     await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None)
                         .ConfigureAwait(false);
 
-                    await video.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService()), CancellationToken.None).ConfigureAwait(false);
+                    _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions());
                 }
                 catch (Exception ex)
                 {
diff --git a/MediaBrowser.Model/Sync/SyncHelper.cs b/MediaBrowser.Api/Sync/SyncHelper.cs
similarity index 91%
rename from MediaBrowser.Model/Sync/SyncHelper.cs
rename to MediaBrowser.Api/Sync/SyncHelper.cs
index 34a5ba9954..6a5b6a927a 100644
--- a/MediaBrowser.Model/Sync/SyncHelper.cs
+++ b/MediaBrowser.Api/Sync/SyncHelper.cs
@@ -1,7 +1,8 @@
 using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Sync;
 using System.Collections.Generic;
 
-namespace MediaBrowser.Model.Sync
+namespace MediaBrowser.Api.Sync
 {
     public static class SyncHelper
     {
@@ -21,6 +22,7 @@ namespace MediaBrowser.Model.Sync
                     if (item.IsVideo)
                     {
                         options.Add(SyncJobOption.Quality);
+                        options.Add(SyncJobOption.Profile);
                         if (items.Count > 1)
                         {
                             options.Add(SyncJobOption.UnwatchedOnly);
@@ -30,6 +32,7 @@ namespace MediaBrowser.Model.Sync
                     if (item.IsFolder && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre)
                     {
                         options.Add(SyncJobOption.Quality);
+                        options.Add(SyncJobOption.Profile);
                         options.Add(SyncJobOption.UnwatchedOnly);
                         break;
                     }
@@ -64,6 +67,7 @@ namespace MediaBrowser.Model.Sync
 
             options.Add(SyncJobOption.Name);
             options.Add(SyncJobOption.Quality);
+            options.Add(SyncJobOption.Profile);
             options.Add(SyncJobOption.UnwatchedOnly);
             options.Add(SyncJobOption.SyncNewContent);
             options.Add(SyncJobOption.ItemLimit);
diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs
index 3f57ca2a04..bcadb4c081 100644
--- a/MediaBrowser.Api/Sync/SyncService.cs
+++ b/MediaBrowser.Api/Sync/SyncService.cs
@@ -94,6 +94,9 @@ namespace MediaBrowser.Api.Sync
         [ApiMember(Name = "ParentId", Description = "ParentId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string ParentId { get; set; }
 
+        [ApiMember(Name = "TargetId", Description = "TargetId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string TargetId { get; set; }
+
         [ApiMember(Name = "Category", Description = "Category", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public SyncCategory? Category { get; set; }
     }
@@ -226,6 +229,21 @@ namespace MediaBrowser.Api.Sync
             result.Targets = _syncManager.GetSyncTargets(request.UserId)
                 .ToList();
 
+            if (!string.IsNullOrWhiteSpace(request.TargetId))
+            {
+                result.Targets = result.Targets
+                    .Where(i => string.Equals(i.Id, request.TargetId, StringComparison.OrdinalIgnoreCase))
+                    .ToList();
+
+                result.QualityOptions = _syncManager
+                    .GetQualityOptions(request.TargetId)
+                    .ToList();
+
+                result.ProfileOptions = _syncManager
+                    .GetProfileOptions(request.TargetId)
+                    .ToList();
+            }
+
             if (request.Category.HasValue)
             {
                 result.Options = SyncHelper.GetSyncOptions(request.Category.Value);
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs
index 9b5ef3a981..a734581f58 100644
--- a/MediaBrowser.Api/UserLibrary/ItemsService.cs
+++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs
@@ -39,6 +39,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string Person { get; set; }
 
+        [ApiMember(Name = "PersonIds", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string PersonIds { get; set; }
+
         /// <summary>
         /// If the Person filter is used, this can also be used to restrict to a specific person type
         /// </summary>
@@ -46,9 +49,6 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public string PersonTypes { get; set; }
 
-        [ApiMember(Name = "AllGenres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
-        public string AllGenres { get; set; }
-
         /// <summary>
         /// Limit results to items containing specific studios
         /// </summary>
@@ -56,6 +56,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "Studios", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Studios { get; set; }
 
+        [ApiMember(Name = "StudioIds", Description = "Optional. If specified, results will be filtered based on studio. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string StudioIds { get; set; }
+        
         /// <summary>
         /// Gets or sets the studios.
         /// </summary>
@@ -63,6 +66,9 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "Artists", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Artists { get; set; }
 
+        [ApiMember(Name = "ArtistIds", Description = "Optional. If specified, results will be filtered based on artist. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
+        public string ArtistIds { get; set; }
+        
         [ApiMember(Name = "Albums", Description = "Optional. If specified, results will be filtered based on album. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
         public string Albums { get; set; }
 
@@ -226,14 +232,14 @@ namespace MediaBrowser.Api.UserLibrary
         [ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? CollapseBoxSetItems { get; set; }
 
-        public string[] GetAllGenres()
+        public string[] GetStudios()
         {
-            return (AllGenres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+            return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
         }
 
-        public string[] GetStudios()
+        public string[] GetStudioIds()
         {
-            return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+            return (StudioIds ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
         }
 
         public string[] GetPersonTypes()
@@ -241,7 +247,12 @@ namespace MediaBrowser.Api.UserLibrary
             return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         }
 
-        public IEnumerable<VideoType> GetVideoTypes()
+        public string[] GetPersonIds()
+        {
+            return (PersonIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+        }
+
+        public VideoType[] GetVideoTypes()
         {
             var val = VideoTypes;
 
@@ -250,7 +261,7 @@ namespace MediaBrowser.Api.UserLibrary
                 return new VideoType[] { };
             }
 
-            return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true));
+            return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
         }
     }
 
@@ -471,9 +482,10 @@ namespace MediaBrowser.Api.UserLibrary
                 Tags = request.GetTags(),
                 OfficialRatings = request.GetOfficialRatings(),
                 Genres = request.GetGenres(),
-                AllGenres = request.GetAllGenres(),
                 Studios = request.GetStudios(),
+                StudioIds = request.GetStudioIds(),
                 Person = request.Person,
+                PersonIds = request.GetPersonIds(),
                 PersonTypes = request.GetPersonTypes(),
                 Years = request.GetYears(),
                 ImageTypes = request.GetImageTypes().ToArray(),
@@ -609,6 +621,8 @@ namespace MediaBrowser.Api.UserLibrary
 
         private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, bool isPreFiltered, ILibraryManager libraryManager)
         {
+            var video = i as Video;
+            
             if (!isPreFiltered)
             {
                 var mediaTypes = request.GetMediaTypes();
@@ -656,7 +670,6 @@ namespace MediaBrowser.Api.UserLibrary
                 if (request.Is3D.HasValue)
                 {
                     var val = request.Is3D.Value;
-                    var video = i as Video;
 
                     if (video == null || val != video.Video3DFormat.HasValue)
                     {
@@ -667,7 +680,6 @@ namespace MediaBrowser.Api.UserLibrary
                 if (request.IsHD.HasValue)
                 {
                     var val = request.IsHD.Value;
-                    var video = i as Video;
 
                     if (video == null || val != video.IsHD)
                     {
@@ -809,8 +821,6 @@ namespace MediaBrowser.Api.UserLibrary
                 {
                     var val = request.HasSubtitles.Value;
 
-                    var video = i as Video;
-
                     if (video == null || val != video.HasSubtitles)
                     {
                         return false;
@@ -930,23 +940,11 @@ namespace MediaBrowser.Api.UserLibrary
                     return false;
                 }
 
-                // Apply genre filter
-                var allGenres = request.GetAllGenres();
-                if (allGenres.Length > 0 && !allGenres.All(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
-                {
-                    return false;
-                }
-
                 // Filter by VideoType
-                if (!string.IsNullOrEmpty(request.VideoTypes))
+                var videoTypes = request.GetVideoTypes();
+                if (videoTypes.Length > 0 && (video == null || !videoTypes.Contains(video.VideoType)))
                 {
-                    var types = request.VideoTypes.Split(',');
-
-                    var video = i as Video;
-                    if (video == null || !types.Contains(video.VideoType.ToString(), StringComparer.OrdinalIgnoreCase))
-                    {
-                        return false;
-                    }
+                    return false;
                 }
 
                 var imageTypes = request.GetImageTypes().ToList();
@@ -965,11 +963,37 @@ namespace MediaBrowser.Api.UserLibrary
                     return false;
                 }
 
+                // Apply studio filter
+                var studioIds = request.GetStudioIds();
+                if (studioIds.Length > 0 && !studioIds.Any(id =>
+                {
+                    var studioItem = libraryManager.GetItemById(id);
+                    return studioItem != null && i.Studios.Contains(studioItem.Name, StringComparer.OrdinalIgnoreCase);
+                }))
+                {
+                    return false;
+                }
+
                 // Apply year filter
                 var years = request.GetYears();
                 if (years.Length > 0 && !(i.ProductionYear.HasValue && years.Contains(i.ProductionYear.Value)))
                 {
                     return false;
+                }            
+                
+                // Apply person filter
+                var personIds = request.GetPersonIds();
+                if (personIds.Length > 0)
+                {
+                    var names = personIds
+                        .Select(libraryManager.GetItemById)
+                        .Select(p => p == null ? "-1" : p.Name)
+                        .ToList();
+
+                    if (!(names.Any(v => i.People.Select(p => p.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
+                    {
+                        return false;
+                    }
                 }
 
                 // Apply person filter
@@ -1030,6 +1054,23 @@ namespace MediaBrowser.Api.UserLibrary
                 }
             }
 
+            // Artists
+            if (!string.IsNullOrEmpty(request.ArtistIds))
+            {
+                var artistIds = request.ArtistIds.Split('|');
+
+                var audio = i as IHasArtist;
+
+                if (!(audio != null && artistIds.Any(id =>
+                {
+                    var artistItem = libraryManager.GetItemById(id);
+                    return artistItem != null && audio.HasAnyArtist(artistItem.Name);
+                })))
+                {
+                    return false;
+                }
+            }
+
             // Artists
             if (!string.IsNullOrEmpty(request.Artists))
             {
@@ -1037,7 +1078,7 @@ namespace MediaBrowser.Api.UserLibrary
 
                 var audio = i as IHasArtist;
 
-                if (!(audio != null && artists.Any(audio.HasArtist)))
+                if (!(audio != null && artists.Any(audio.HasAnyArtist)))
                 {
                     return false;
                 }
diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
index fae83e3692..55e1681e0d 100644
--- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs
+++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs
@@ -231,7 +231,7 @@ namespace MediaBrowser.Api.UserLibrary
                 datePlayed = DateTime.ParseExact(request.DatePlayed, "yyyyMMddHHmmss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
             }
 
-            var session = GetSession();
+            var session = await GetSession().ConfigureAwait(false);
 
             var dto = await UpdatePlayedStatus(user, request.Id, true, datePlayed).ConfigureAwait(false);
 
@@ -266,7 +266,7 @@ namespace MediaBrowser.Api.UserLibrary
 
         public void Post(ReportPlaybackStart request)
         {
-            request.SessionId = GetSession().Id;
+            request.SessionId = GetSession().Result.Id;
 
             var task = _sessionManager.OnPlaybackStart(request);
 
@@ -294,7 +294,7 @@ namespace MediaBrowser.Api.UserLibrary
 
         public void Post(ReportPlaybackProgress request)
         {
-            request.SessionId = GetSession().Id;
+            request.SessionId = GetSession().Result.Id;
 
             var task = _sessionManager.OnPlaybackProgress(request);
 
@@ -317,7 +317,7 @@ namespace MediaBrowser.Api.UserLibrary
 
         public void Post(ReportPlaybackStopped request)
         {
-            request.SessionId = GetSession().Id;
+            request.SessionId = GetSession().Result.Id;
 
             var task = _sessionManager.OnPlaybackStopped(request);
 
@@ -339,7 +339,7 @@ namespace MediaBrowser.Api.UserLibrary
         {
             var user = _userManager.GetUserById(request.UserId);
 
-            var session = GetSession();
+            var session = await GetSession().ConfigureAwait(false);
 
             var dto = await UpdatePlayedStatus(user, request.Id, false, null).ConfigureAwait(false);
 
diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs
index c17f333481..3996a03114 100644
--- a/MediaBrowser.Api/UserService.cs
+++ b/MediaBrowser.Api/UserService.cs
@@ -253,18 +253,14 @@ namespace MediaBrowser.Api
         /// The _user manager
         /// </summary>
         private readonly IUserManager _userManager;
-        private readonly IDtoService _dtoService;
         private readonly ISessionManager _sessionMananger;
         private readonly IServerConfigurationManager _config;
         private readonly INetworkManager _networkManager;
         private readonly IDeviceManager _deviceManager;
 
-        public IAuthorizationContext AuthorizationContext { get; set; }
-
-        public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager, IDeviceManager deviceManager)
+        public UserService(IUserManager userManager, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager, IDeviceManager deviceManager)
         {
             _userManager = userManager;
-            _dtoService = dtoService;
             _sessionMananger = sessionMananger;
             _config = config;
             _networkManager = networkManager;
@@ -464,7 +460,7 @@ namespace MediaBrowser.Api
 
         public async Task PostAsync(UpdateUserPassword request)
         {
-            AssertCanUpdateUser(request.Id);
+            AssertCanUpdateUser(_userManager, request.Id);
 
             var user = _userManager.GetUserById(request.Id);
 
@@ -498,7 +494,7 @@ namespace MediaBrowser.Api
         
         public async Task PostAsync(UpdateUserEasyPassword request)
         {
-            AssertCanUpdateUser(request.Id);
+            AssertCanUpdateUser(_userManager, request.Id);
             
             var user = _userManager.GetUserById(request.Id);
 
@@ -534,7 +530,7 @@ namespace MediaBrowser.Api
             // https://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Text/ServiceStack.Text/Controller/PathInfo.cs
             var id = GetPathValue(1);
 
-            AssertCanUpdateUser(id);
+            AssertCanUpdateUser(_userManager, id);
 
             var dtoUser = request;
 
@@ -584,29 +580,13 @@ namespace MediaBrowser.Api
 
         public void Post(UpdateUserConfiguration request)
         {
-            AssertCanUpdateUser(request.Id);
+            AssertCanUpdateUser(_userManager, request.Id);
 
             var task = _userManager.UpdateConfiguration(request.Id, request);
 
             Task.WaitAll(task);
         }
 
-        private void AssertCanUpdateUser(string userId)
-        {
-            var auth = AuthorizationContext.GetAuthorizationInfo(Request);
-
-            // If they're going to update the record of another user, they must be an administrator
-            if (!string.Equals(userId, auth.UserId, StringComparison.OrdinalIgnoreCase))
-            {
-                var authenticatedUser = _userManager.GetUserById(auth.UserId);
-
-                if (!authenticatedUser.Policy.IsAdministrator)
-                {
-                    throw new SecurityException("Unauthorized access.");
-                }
-            }
-        }
-
         public void Post(UpdateUserPolicy request)
         {
             var task = UpdateUserPolicy(request);
diff --git a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
index 3d759ca545..cdcbc311a1 100644
--- a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
+++ b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
@@ -5,6 +5,7 @@ using SharpCompress.Archive.Tar;
 using SharpCompress.Common;
 using SharpCompress.Reader;
 using SharpCompress.Reader.Zip;
+using System;
 using System.IO;
 
 namespace MediaBrowser.Common.Implementations.Archiving
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index 4d6cc16089..78dcea493e 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -313,7 +313,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// </summary>
         /// <param name="sender">The source of the event.</param>
         /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
-        async void trigger_Triggered(object sender, EventArgs e)
+        async void trigger_Triggered(object sender, GenericEventArgs<TaskExecutionOptions> e)
         {
             var trigger = (ITaskTrigger)sender;
 
@@ -340,11 +340,12 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// <summary>
         /// Executes the task
         /// </summary>
+        /// <param name="options">Task options.</param>
         /// <returns>Task.</returns>
         /// <exception cref="System.InvalidOperationException">Cannot execute a Task that is already running</exception>
-        public async Task Execute()
+        public async Task Execute(TaskExecutionOptions options)
         {
-            var task = ExecuteInternal();
+            var task = ExecuteInternal(options);
 
             _currentTask = task;
 
@@ -358,7 +359,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
             }
         }
 
-        private async Task ExecuteInternal()
+        private async Task ExecuteInternal(TaskExecutionOptions options)
         {
             // Cancel the current execution, if any
             if (CurrentCancellationTokenSource != null)
@@ -383,7 +384,14 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
 
             try
             {
-                await ExecuteTask(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false);
+                var localTask = ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress);
+
+                if (options != null && options.MaxRuntimeMs.HasValue)
+                {
+                    CurrentCancellationTokenSource.CancelAfter(options.MaxRuntimeMs.Value);
+                }
+
+                await localTask.ConfigureAwait(false);
 
                 status = TaskCompletionStatus.Completed;
             }
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
index 5a3ac53dc7..4f84652c60 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/TaskManager.cs
@@ -29,7 +29,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// <summary>
         /// The _task queue
         /// </summary>
-        private readonly List<Type> _taskQueue = new List<Type>();
+        private readonly SortedDictionary<Type, TaskExecutionOptions> _taskQueue = new SortedDictionary<Type, TaskExecutionOptions>();
 
         /// <summary>
         /// Gets or sets the json serializer.
@@ -69,13 +69,20 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// Cancels if running and queue.
         /// </summary>
         /// <typeparam name="T"></typeparam>
-        public void CancelIfRunningAndQueue<T>()
+        /// <param name="options">Task options.</param>
+        public void CancelIfRunningAndQueue<T>(TaskExecutionOptions options)
                  where T : IScheduledTask
         {
             var task = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
             ((ScheduledTaskWorker)task).CancelIfRunning();
 
-            QueueScheduledTask<T>();
+            QueueScheduledTask<T>(options);
+        }
+
+        public void CancelIfRunningAndQueue<T>()
+               where T : IScheduledTask
+        {
+            CancelIfRunningAndQueue<T>(new TaskExecutionOptions());
         }
 
         /// <summary>
@@ -93,30 +100,39 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
         /// Queues the scheduled task.
         /// </summary>
         /// <typeparam name="T"></typeparam>
-        public void QueueScheduledTask<T>()
+        /// <param name="options">Task options</param>
+        public void QueueScheduledTask<T>(TaskExecutionOptions options)
             where T : IScheduledTask
         {
             var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == typeof(T));
 
-            QueueScheduledTask(scheduledTask);
+            QueueScheduledTask(scheduledTask, options);
         }
 
+        public void QueueScheduledTask<T>()
+            where T : IScheduledTask
+        {
+            QueueScheduledTask<T>(new TaskExecutionOptions());
+        }
+        
         /// <summary>
         /// Queues the scheduled task.
         /// </summary>
         /// <param name="task">The task.</param>
-        public void QueueScheduledTask(IScheduledTask task)
+        /// <param name="options">The task options.</param>
+        public void QueueScheduledTask(IScheduledTask task, TaskExecutionOptions options)
         {
             var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == task.GetType());
 
-            QueueScheduledTask(scheduledTask);
+            QueueScheduledTask(scheduledTask, options);
         }
 
         /// <summary>
         /// Queues the scheduled task.
         /// </summary>
         /// <param name="task">The task.</param>
-        private void QueueScheduledTask(IScheduledTaskWorker task)
+        /// <param name="options">The task options.</param>
+        private void QueueScheduledTask(IScheduledTaskWorker task, TaskExecutionOptions options)
         {
             var type = task.ScheduledTask.GetType();
 
@@ -125,17 +141,18 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
                 // If it's idle just execute immediately
                 if (task.State == TaskState.Idle)
                 {
-                    Execute(task);
+                    Execute(task, options);
                     return;
                 }
 
-                if (!_taskQueue.Contains(type))
+                if (!_taskQueue.ContainsKey(type))
                 {
                     Logger.Info("Queueing task {0}", type.Name);
-                    _taskQueue.Add(type);
+                    _taskQueue.Add(type, options);
                 }
                 else
                 {
+                    _taskQueue[type] = options;
                     Logger.Info("Task already queued: {0}", type.Name);
                 }
             }
@@ -181,9 +198,9 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
             ((ScheduledTaskWorker)task).Cancel();
         }
 
-        public Task Execute(IScheduledTaskWorker task)
+        public Task Execute(IScheduledTaskWorker task, TaskExecutionOptions options)
         {
-            return ((ScheduledTaskWorker)task).Execute();
+            return ((ScheduledTaskWorker)task).Execute(options);
         }
 
         /// <summary>
@@ -224,15 +241,15 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks
             // Execute queued tasks
             lock (_taskQueue)
             {
-                foreach (var type in _taskQueue.ToList())
+                foreach (var enqueuedType in _taskQueue.ToList())
                 {
-                    var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == type);
+                    var scheduledTask = ScheduledTasks.First(t => t.ScheduledTask.GetType() == enqueuedType.Key);
 
                     if (scheduledTask.State == TaskState.Idle)
                     {
-                        Execute(scheduledTask);
+                        Execute(scheduledTask, enqueuedType.Value);
 
-                        _taskQueue.Remove(type);
+                        _taskQueue.Remove(enqueuedType.Key);
                     }
                 }
             }
diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index 779f992d32..eb2b46c223 100644
--- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -118,9 +118,23 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
                 index++;
             }
 
+            DeleteEmptyFolders(directory);
+
             progress.Report(100);
         }
 
+        private static void DeleteEmptyFolders(string parent)
+        {
+            foreach (var directory in Directory.GetDirectories(parent))
+            {
+                DeleteEmptyFolders(directory);
+                if (!Directory.EnumerateFileSystemEntries(directory).Any())
+                {
+                    Directory.Delete(directory, false);
+                }
+            }
+        }
+
         private void DeleteFile(string path)
         {
             try
diff --git a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
index e7fd121788..b49551ea99 100644
--- a/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
+++ b/MediaBrowser.Common.Implementations/Serialization/JsonSerializer.cs
@@ -59,6 +59,11 @@ namespace MediaBrowser.Common.Implementations.Serialization
             }
         }
 
+        private Stream OpenFile(string path)
+        {
+            return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
+        }
+
         /// <summary>
         /// Deserializes from file.
         /// </summary>
@@ -78,7 +83,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
                 throw new ArgumentNullException("file");
             }
 
-            using (Stream stream = File.OpenRead(file))
+            using (Stream stream = OpenFile(file))
             {
                 return DeserializeFromStream(stream, type);
             }
@@ -99,7 +104,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
                 throw new ArgumentNullException("file");
             }
 
-            using (Stream stream = File.OpenRead(file))
+            using (Stream stream = OpenFile(file))
             {
                 return DeserializeFromStream<T>(stream);
             }
diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj
index c46dd4a4f6..ad0c0cecdb 100644
--- a/MediaBrowser.Common/MediaBrowser.Common.csproj
+++ b/MediaBrowser.Common/MediaBrowser.Common.csproj
@@ -86,6 +86,7 @@
     <Compile Include="ScheduledTasks\DailyTrigger.cs" />
     <Compile Include="ScheduledTasks\IntervalTrigger.cs" />
     <Compile Include="ScheduledTasks\TaskCompletionEventArgs.cs" />
+    <Compile Include="ScheduledTasks\TaskExecutionOptions.cs" />
     <Compile Include="ScheduledTasks\WeeklyTrigger.cs" />
     <Compile Include="Security\IRequiresRegistration.cs" />
     <Compile Include="Security\ISecurityManager.cs" />
diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs
index 9d0133c67c..a0716137b9 100644
--- a/MediaBrowser.Common/Plugins/BasePlugin.cs
+++ b/MediaBrowser.Common/Plugins/BasePlugin.cs
@@ -325,7 +325,7 @@ namespace MediaBrowser.Common.Plugins
                 AssemblyFileName = AssemblyFileName,
                 ConfigurationDateLastModified = ConfigurationDateLastModified,
                 Description = Description,
-                Id = Id.ToString("N"),
+                Id = Id.ToString(),
                 ConfigurationFileName = ConfigurationFileName
             };
 
diff --git a/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs b/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
index bfecadee7c..2f935607bf 100644
--- a/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/DailyTrigger.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Threading;
+using MediaBrowser.Model.Events;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
@@ -20,6 +21,14 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <value>The timer.</value>
         private Timer Timer { get; set; }
 
+        /// <summary>
+        /// Gets the execution properties of this task.
+        /// </summary>
+        /// <value>
+        /// The execution properties of this task.
+        /// </value>
+        public TaskExecutionOptions TaskOptions { get; set; }
+
         /// <summary>
         /// Stars waiting for the trigger action
         /// </summary>
@@ -58,7 +67,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Occurs when [triggered].
         /// </summary>
-        public event EventHandler<EventArgs> Triggered;
+        public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
 
         /// <summary>
         /// Called when [triggered].
@@ -67,7 +76,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             if (Triggered != null)
             {
-                Triggered(this, EventArgs.Empty);
+                Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
             }
         }
     }
diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
index 01dc355c33..8d271859e6 100644
--- a/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
+++ b/MediaBrowser.Common/ScheduledTasks/ITaskManager.cs
@@ -13,6 +13,14 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <value>The scheduled tasks.</value>
         IScheduledTaskWorker[] ScheduledTasks { get; }
 
+        /// <summary>
+        /// Cancels if running and queue.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="options">Task options.</param>
+        void CancelIfRunningAndQueue<T>(TaskExecutionOptions options)
+            where T : IScheduledTask;
+
         /// <summary>
         /// Cancels if running and queue.
         /// </summary>
@@ -27,6 +35,14 @@ namespace MediaBrowser.Common.ScheduledTasks
         void CancelIfRunning<T>()
             where T : IScheduledTask;
 
+        /// <summary>
+        /// Queues the scheduled task.
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="options">Task options.</param>
+        void QueueScheduledTask<T>(TaskExecutionOptions options)
+            where T : IScheduledTask;
+
         /// <summary>
         /// Queues the scheduled task.
         /// </summary>
@@ -38,7 +54,8 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Queues the scheduled task.
         /// </summary>
         /// <param name="task">The task.</param>
-        void QueueScheduledTask(IScheduledTask task);
+        /// <param name="options">The task run options.</param>
+        void QueueScheduledTask(IScheduledTask task, TaskExecutionOptions options = null);
 
         /// <summary>
         /// Adds the tasks.
@@ -47,7 +64,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         void AddTasks(IEnumerable<IScheduledTask> tasks);
 
         void Cancel(IScheduledTaskWorker task);
-        Task Execute(IScheduledTaskWorker task);
+        Task Execute(IScheduledTaskWorker task, TaskExecutionOptions options = null);
 
         event EventHandler<GenericEventArgs<IScheduledTaskWorker>> TaskExecuting;
         event EventHandler<TaskCompletionEventArgs> TaskCompleted;
diff --git a/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs b/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
index 66701650e1..d30111316a 100644
--- a/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/ITaskTrigger.cs
@@ -1,4 +1,5 @@
 using System;
+using MediaBrowser.Model.Events;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
@@ -10,7 +11,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Fires when the trigger condition is satisfied and the task should run
         /// </summary>
-        event EventHandler<EventArgs> Triggered;
+        event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
 
         /// <summary>
         /// Stars waiting for the trigger action
@@ -22,5 +23,13 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// Stops waiting for the trigger action
         /// </summary>
         void Stop();
+
+        /// <summary>
+        /// Gets or sets the execution properties of this task.
+        /// </summary>
+        /// <value>
+        /// The execution properties of this task.
+        /// </value>
+        TaskExecutionOptions TaskOptions { get; set; }
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
index cac6d1fa35..455a70d7e5 100644
--- a/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/IntervalTrigger.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Threading;
+using MediaBrowser.Model.Events;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
@@ -20,6 +21,14 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <value>The timer.</value>
         private Timer Timer { get; set; }
 
+        /// <summary>
+        /// Gets the execution properties of this task.
+        /// </summary>
+        /// <value>
+        /// The execution properties of this task.
+        /// </value>
+        public TaskExecutionOptions TaskOptions { get; set; }
+
         /// <summary>
         /// Stars waiting for the trigger action
         /// </summary>
@@ -53,7 +62,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Occurs when [triggered].
         /// </summary>
-        public event EventHandler<EventArgs> Triggered;
+        public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
 
         /// <summary>
         /// Called when [triggered].
@@ -62,7 +71,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             if (Triggered != null)
             {
-                Triggered(this, EventArgs.Empty);
+                Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
             }
         }
     }
diff --git a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs
index cec6249b34..4ad33341ad 100644
--- a/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs
+++ b/MediaBrowser.Common/ScheduledTasks/ScheduledTaskHelpers.cs
@@ -99,6 +99,11 @@ namespace MediaBrowser.Common.ScheduledTasks
                 info.SystemEvent = systemEventTrigger.SystemEvent;
             }
 
+            if (trigger.TaskOptions != null)
+            {
+                info.MaxRuntimeMs = trigger.TaskOptions.MaxRuntimeMs;
+            }
+
             return info;
         }
 
@@ -111,6 +116,11 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <exception cref="System.ArgumentException">Invalid trigger type:  + info.Type</exception>
         public static ITaskTrigger GetTrigger(TaskTriggerInfo info)
         {
+            var options = new TaskExecutionOptions
+            {
+                MaxRuntimeMs = info.MaxRuntimeMs
+            };
+
             if (info.Type.Equals(typeof(DailyTrigger).Name, StringComparison.OrdinalIgnoreCase))
             {
                 if (!info.TimeOfDayTicks.HasValue)
@@ -120,7 +130,8 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 return new DailyTrigger
                 {
-                    TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value)
+                    TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value),
+                    TaskOptions = options
                 };
             }
 
@@ -139,7 +150,8 @@ namespace MediaBrowser.Common.ScheduledTasks
                 return new WeeklyTrigger
                 {
                     TimeOfDay = TimeSpan.FromTicks(info.TimeOfDayTicks.Value),
-                    DayOfWeek = info.DayOfWeek.Value
+                    DayOfWeek = info.DayOfWeek.Value,
+                    TaskOptions = options
                 };
             }
 
@@ -152,7 +164,8 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 return new IntervalTrigger
                 {
-                    Interval = TimeSpan.FromTicks(info.IntervalTicks.Value)
+                    Interval = TimeSpan.FromTicks(info.IntervalTicks.Value),
+                    TaskOptions = options
                 };
             }
 
@@ -165,7 +178,8 @@ namespace MediaBrowser.Common.ScheduledTasks
 
                 return new SystemEventTrigger
                 {
-                    SystemEvent = info.SystemEvent.Value
+                    SystemEvent = info.SystemEvent.Value,
+                    TaskOptions = options
                 };
             }
 
diff --git a/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs b/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
index 17e4628d05..a58fa22b9b 100644
--- a/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/StartupTrigger.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
@@ -10,6 +11,14 @@ namespace MediaBrowser.Common.ScheduledTasks
     {
         public int DelayMs { get; set; }
 
+        /// <summary>
+        /// Gets the execution properties of this task.
+        /// </summary>
+        /// <value>
+        /// The execution properties of this task.
+        /// </value>
+        public TaskExecutionOptions TaskOptions { get; set; }
+
         public StartupTrigger()
         {
             DelayMs = 3000;
@@ -39,7 +48,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Occurs when [triggered].
         /// </summary>
-        public event EventHandler<EventArgs> Triggered;
+        public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
 
         /// <summary>
         /// Called when [triggered].
@@ -48,7 +57,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             if (Triggered != null)
             {
-                Triggered(this, EventArgs.Empty);
+                Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
             }
         }
     }
diff --git a/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs b/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
index 7f86a5a2f1..a40dc6b5cb 100644
--- a/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/SystemEventTrigger.cs
@@ -2,6 +2,7 @@
 using Microsoft.Win32;
 using System;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
@@ -16,6 +17,14 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <value>The system event.</value>
         public SystemEvent SystemEvent { get; set; }
 
+        /// <summary>
+        /// Gets the execution properties of this task.
+        /// </summary>
+        /// <value>
+        /// The execution properties of this task.
+        /// </value>
+        public TaskExecutionOptions TaskOptions { get; set; }
+
         /// <summary>
         /// Stars waiting for the trigger action
         /// </summary>
@@ -57,7 +66,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Occurs when [triggered].
         /// </summary>
-        public event EventHandler<EventArgs> Triggered;
+        public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
 
         /// <summary>
         /// Called when [triggered].
@@ -66,7 +75,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             if (Triggered != null)
             {
-                Triggered(this, EventArgs.Empty);
+                Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
             }
         }
     }
diff --git a/MediaBrowser.Common/ScheduledTasks/TaskExecutionOptions.cs b/MediaBrowser.Common/ScheduledTasks/TaskExecutionOptions.cs
new file mode 100644
index 0000000000..41b33b1c26
--- /dev/null
+++ b/MediaBrowser.Common/ScheduledTasks/TaskExecutionOptions.cs
@@ -0,0 +1,11 @@
+
+namespace MediaBrowser.Common.ScheduledTasks
+{
+    /// <summary>
+    /// A class that encomposases all common task run properties.
+    /// </summary>
+    public class TaskExecutionOptions
+    {
+        public int? MaxRuntimeMs { get; set; }
+    }
+}
diff --git a/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs b/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
index cfb3f1fab3..a3818f83fd 100644
--- a/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
+++ b/MediaBrowser.Common/ScheduledTasks/WeeklyTrigger.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Threading;
+using MediaBrowser.Model.Events;
 
 namespace MediaBrowser.Common.ScheduledTasks
 {
@@ -20,6 +21,14 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <value>The day of week.</value>
         public DayOfWeek DayOfWeek { get; set; }
 
+        /// <summary>
+        /// Gets the execution properties of this task.
+        /// </summary>
+        /// <value>
+        /// The execution properties of this task.
+        /// </value>
+        public TaskExecutionOptions TaskOptions { get; set; }
+
         /// <summary>
         /// Gets or sets the timer.
         /// </summary>
@@ -88,7 +97,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         /// <summary>
         /// Occurs when [triggered].
         /// </summary>
-        public event EventHandler<EventArgs> Triggered;
+        public event EventHandler<GenericEventArgs<TaskExecutionOptions>> Triggered;
 
         /// <summary>
         /// Called when [triggered].
@@ -97,7 +106,7 @@ namespace MediaBrowser.Common.ScheduledTasks
         {
             if (Triggered != null)
             {
-                Triggered(this, EventArgs.Empty);
+                Triggered(this, new GenericEventArgs<TaskExecutionOptions>(TaskOptions));
             }
         }
     }
diff --git a/MediaBrowser.Controller/Connect/ConnectSupporterSummary.cs b/MediaBrowser.Controller/Connect/ConnectSupporterSummary.cs
new file mode 100644
index 0000000000..20eef0521b
--- /dev/null
+++ b/MediaBrowser.Controller/Connect/ConnectSupporterSummary.cs
@@ -0,0 +1,19 @@
+using MediaBrowser.Model.Connect;
+using System.Collections.Generic;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Controller.Connect
+{
+    public class ConnectSupporterSummary
+    {
+        public int MaxUsers { get; set; }
+        public List<ConnectUser> Users { get; set; }
+        public List<UserDto> EligibleUsers { get; set; }
+
+        public ConnectSupporterSummary()
+        {
+            Users = new List<ConnectUser>();
+            EligibleUsers = new List<UserDto>();
+        }
+    }
+}
diff --git a/MediaBrowser.Controller/Connect/IConnectManager.cs b/MediaBrowser.Controller/Connect/IConnectManager.cs
index a0ab1f9b65..7eecf6ebff 100644
--- a/MediaBrowser.Controller/Connect/IConnectManager.cs
+++ b/MediaBrowser.Controller/Connect/IConnectManager.cs
@@ -69,5 +69,25 @@ namespace MediaBrowser.Controller.Connect
         /// <param name="token">The token.</param>
         /// <returns><c>true</c> if [is authorization token valid] [the specified token]; otherwise, <c>false</c>.</returns>
         bool IsAuthorizationTokenValid(string token);
+
+        /// <summary>
+        /// Gets the connect supporter summary.
+        /// </summary>
+        /// <returns>Task&lt;ConnectSupporterSummary&gt;.</returns>
+        Task<ConnectSupporterSummary> GetConnectSupporterSummary();
+
+        /// <summary>
+        /// Removes the connect supporter.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Task.</returns>
+        Task RemoveConnectSupporter(string id);
+
+        /// <summary>
+        /// Adds the connect supporter.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Task.</returns>
+        Task AddConnectSupporter(string id);
     }
 }
diff --git a/MediaBrowser.Controller/Devices/IDeviceManager.cs b/MediaBrowser.Controller/Devices/IDeviceManager.cs
index 78eebd9942..2846bcfc64 100644
--- a/MediaBrowser.Controller/Devices/IDeviceManager.cs
+++ b/MediaBrowser.Controller/Devices/IDeviceManager.cs
@@ -25,9 +25,10 @@ namespace MediaBrowser.Controller.Devices
         /// <param name="reportedId">The reported identifier.</param>
         /// <param name="name">The name.</param>
         /// <param name="appName">Name of the application.</param>
+        /// <param name="appVersion">The application version.</param>
         /// <param name="usedByUserId">The used by user identifier.</param>
         /// <returns>Task.</returns>
-        Task<DeviceInfo> RegisterDevice(string reportedId, string name, string appName, string usedByUserId);
+        Task<DeviceInfo> RegisterDevice(string reportedId, string name, string appName, string appVersion, string usedByUserId);
 
         /// <summary>
         /// Saves the capabilities.
diff --git a/MediaBrowser.Controller/Diagnostics/IProcessManager.cs b/MediaBrowser.Controller/Diagnostics/IProcessManager.cs
new file mode 100644
index 0000000000..2e076bd882
--- /dev/null
+++ b/MediaBrowser.Controller/Diagnostics/IProcessManager.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics;
+
+namespace MediaBrowser.Controller.Diagnostics
+{
+    /// <summary>
+    /// Interface IProcessManager
+    /// </summary>
+    public interface IProcessManager
+    {
+        /// <summary>
+        /// Gets a value indicating whether [supports suspension].
+        /// </summary>
+        /// <value><c>true</c> if [supports suspension]; otherwise, <c>false</c>.</value>
+        bool SupportsSuspension { get; }
+
+        /// <summary>
+        /// Suspends the process.
+        /// </summary>
+        /// <param name="process">The process.</param>
+        void SuspendProcess(Process process);
+
+        /// <summary>
+        /// Resumes the process.
+        /// </summary>
+        /// <param name="process">The process.</param>
+        void ResumeProcess(Process process);
+    }
+}
diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
index 8ac7d56d29..6fafc2b464 100644
--- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs
+++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs
@@ -2,7 +2,6 @@
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
-using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Threading.Tasks;
@@ -30,10 +29,9 @@ namespace MediaBrowser.Controller.Drawing
         /// <summary>
         /// Gets the size of the image.
         /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="imageDateModified">The image date modified.</param>
+        /// <param name="info">The information.</param>
         /// <returns>ImageSize.</returns>
-        ImageSize GetImageSize(string path, DateTime imageDateModified);
+        ImageSize GetImageSize(ItemImageInfo info);
 
         /// <summary>
         /// Adds the parts.
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 9024479999..100633d7ff 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
@@ -22,7 +21,8 @@ namespace MediaBrowser.Controller.Entities.Audio
         IHasLookupInfo<SongInfo>,
         IHasTags,
         IHasMediaSources,
-        IThemeMedia
+        IThemeMedia,
+        IArchivable
     {
         public string FormatName { get; set; }
         public long? Size { get; set; }
@@ -171,16 +171,6 @@ namespace MediaBrowser.Controller.Entities.Audio
                     + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
         }
 
-        /// <summary>
-        /// Determines whether the specified name has artist.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
-        public bool HasArtist(string name)
-        {
-            return AllArtists.Contains(name, StringComparer.OrdinalIgnoreCase);
-        }
-
         /// <summary>
         /// Gets the user data key.
         /// </summary>
@@ -239,7 +229,7 @@ namespace MediaBrowser.Controller.Entities.Audio
             {
                 Id = i.Id.ToString("N"),
                 Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
-                MediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(),
+                MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
                 Name = i.Name,
                 Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
                 RunTimeTicks = i.RunTimeTicks,
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
index a20f053232..56921409ae 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasAlbumArtist.cs
@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace MediaBrowser.Controller.Entities.Audio
 {
@@ -9,10 +11,20 @@ namespace MediaBrowser.Controller.Entities.Audio
 
     public interface IHasArtist
     {
-        bool HasArtist(string name);
-
         List<string> AllArtists { get; }
 
-        List<string> Artists { get; }
+        List<string> Artists { get; set; }
+    }
+
+    public static class HasArtistExtensions
+    {
+        public static bool HasArtist(this IHasArtist hasArtist, string artist)
+        {
+            return hasArtist.Artists.Contains(artist, StringComparer.OrdinalIgnoreCase);
+        }
+        public static bool HasAnyArtist(this IHasArtist hasArtist, string artist)
+        {
+            return hasArtist.AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase);
+        }
     }
 }
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index e3f523b5a7..dc3f13b01d 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -120,16 +120,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             get { return Parent as MusicArtist ?? UnknwonArtist; }
         }
 
-        /// <summary>
-        /// Determines whether the specified artist has artist.
-        /// </summary>
-        /// <param name="artist">The artist.</param>
-        /// <returns><c>true</c> if the specified artist has artist; otherwise, <c>false</c>.</returns>
-        public bool HasArtist(string artist)
-        {
-            return AllArtists.Contains(artist, StringComparer.OrdinalIgnoreCase);
-        }
-
         public List<string> Artists { get; set; }
 
         /// <summary>
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 2b81450414..4185590ab3 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Users;
@@ -148,12 +149,15 @@ namespace MediaBrowser.Controller.Entities.Audio
             var totalItems = songs.Count + others.Count;
             var numComplete = 0;
 
+            var childUpdateType = ItemUpdateType.None;
+
             // Refresh songs
             foreach (var item in songs)
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
-                await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+                var updateType = await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+                childUpdateType = childUpdateType | updateType;
 
                 numComplete++;
                 double percent = numComplete;
@@ -161,15 +165,22 @@ namespace MediaBrowser.Controller.Entities.Audio
                 progress.Report(percent * 100);
             }
 
+            var parentRefreshOptions = refreshOptions;
+            if (childUpdateType > ItemUpdateType.None)
+            {
+                parentRefreshOptions = new MetadataRefreshOptions(refreshOptions);
+                parentRefreshOptions.MetadataRefreshMode = MetadataRefreshMode.FullRefresh;
+            }
+
             // Refresh current item
-            await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+            await RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
 
             // Refresh all non-songs
             foreach (var item in others)
             {
                 cancellationToken.ThrowIfCancellationRequested();
 
-                await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
+                var updateType = await item.RefreshMetadata(parentRefreshOptions, cancellationToken).ConfigureAwait(false);
 
                 numComplete++;
                 double percent = numComplete;
@@ -202,7 +213,7 @@ namespace MediaBrowser.Controller.Entities.Audio
             return i =>
             {
                 var hasArtist = i as IHasArtist;
-                return hasArtist != null && hasArtist.HasArtist(Name);
+                return hasArtist != null && hasArtist.HasAnyArtist(Name);
             };
         }
     }
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 50a6dda305..dd6189bc57 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -239,6 +239,11 @@ namespace MediaBrowser.Controller.Entities
             get { return this.GetImagePath(ImageType.Primary); }
         }
 
+        public virtual bool IsInternetMetadataEnabled()
+        {
+            return ConfigurationManager.Configuration.EnableInternetProviders;
+        }
+
         public virtual bool CanDelete()
         {
             var locationType = LocationType;
@@ -717,7 +722,7 @@ namespace MediaBrowser.Controller.Entities
         /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>true if a provider reports we changed</returns>
-        public async Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken)
+        public async Task<ItemUpdateType> RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
             var locationType = LocationType;
 
@@ -744,15 +749,16 @@ namespace MediaBrowser.Controller.Entities
                 }
             }
 
-            var dateLastSaved = DateLastSaved;
+            var refreshOptions = requiresSave
+                ? new MetadataRefreshOptions(options)
+                {
+                    ForceSave = true
+                }
+                : options;
 
-            await ProviderManager.RefreshMetadata(this, options, cancellationToken).ConfigureAwait(false);
+            var result = await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
 
-            // If it wasn't saved by the provider process, save now
-            if (requiresSave && dateLastSaved == DateLastSaved)
-            {
-                await UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
-            }
+            return result;
         }
 
         [IgnoreDataMember]
@@ -1245,13 +1251,6 @@ namespace MediaBrowser.Controller.Entities
                     {
                         if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase))
                         {
-                            if (info.ItemYear.HasValue)
-                            {
-                                if (info.ItemYear.Value != (i.ProductionYear ?? -1))
-                                {
-                                    return false;
-                                }
-                            }
                             return true;
                         }
                     }
@@ -1461,7 +1460,8 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>Task.</returns>
         public virtual Task ChangedExternally()
         {
-            return RefreshMetadata(CancellationToken.None);
+            ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions());
+            return Task.FromResult(true);
         }
 
         /// <summary>
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 0d9bb03acf..cffc0989a5 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1135,10 +1135,7 @@ namespace MediaBrowser.Controller.Entities
             foreach (var child in LinkedChildren)
             {
                 // Reset the cached value
-                if (child.ItemId.HasValue && child.ItemId.Value == Guid.Empty)
-                {
-                    child.ItemId = null;
-                }
+                child.ItemId = null;
             }
 
             return false;
diff --git a/MediaBrowser.Controller/Entities/IArchivable.cs b/MediaBrowser.Controller/Entities/IArchivable.cs
new file mode 100644
index 0000000000..575d203a7c
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/IArchivable.cs
@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Controller.Entities
+{
+    public interface IArchivable
+    {
+        bool IsArchive { get; }
+    }
+}
diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs
index 5aafc8eb31..00a42271b5 100644
--- a/MediaBrowser.Controller/Entities/IHasImages.cs
+++ b/MediaBrowser.Controller/Entities/IHasImages.cs
@@ -184,6 +184,12 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <value><c>true</c> if [always scan internal metadata path]; otherwise, <c>false</c>.</value>
         bool AlwaysScanInternalMetadataPath { get; }
+
+        /// <summary>
+        /// Determines whether [is internet metadata enabled].
+        /// </summary>
+        /// <returns><c>true</c> if [is internet metadata enabled]; otherwise, <c>false</c>.</returns>
+        bool IsInternetMetadataEnabled();
     }
 
     public static class HasImagesExtensions
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index 98d2682989..17a1478068 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -1,9 +1,6 @@
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Dto;
 using System;
 using System.Collections.Generic;
-using System.Linq;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -22,53 +19,4 @@ namespace MediaBrowser.Controller.Entities
         /// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
         IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
     }
-
-    public static class HasMediaSourceExtensions
-    {
-        public static IEnumerable<MediaSourceInfo> GetMediaSources(this IHasMediaSources item, bool enablePathSubstitution, User user)
-        {
-            if (item == null)
-            {
-                throw new ArgumentNullException("item");
-            }
-
-            if (!(item is Video))
-            {
-                return item.GetMediaSources(enablePathSubstitution);
-            }
-
-            if (user == null)
-            {
-                throw new ArgumentNullException("user");
-            }
-
-            var sources = item.GetMediaSources(enablePathSubstitution).ToList();
-
-            var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
-            ? new string[] { }
-            : new[] { user.Configuration.AudioLanguagePreference };
-
-            var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
-                ? new List<string> { }
-                : new List<string> { user.Configuration.SubtitleLanguagePreference };
-
-            foreach (var source in sources)
-            {
-                source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(
-                    source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
-
-                var defaultAudioIndex = source.DefaultAudioStreamIndex;
-                var audioLangage = defaultAudioIndex == null
-                    ? null
-                    : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
-
-                source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
-                    preferredSubs,
-                    user.Configuration.SubtitleMode,
-                    audioLangage);
-            }
-
-            return sources;
-        }
-    }
 }
diff --git a/MediaBrowser.Controller/Entities/IHasOriginalTitle.cs b/MediaBrowser.Controller/Entities/IHasOriginalTitle.cs
new file mode 100644
index 0000000000..6f5cb59bc0
--- /dev/null
+++ b/MediaBrowser.Controller/Entities/IHasOriginalTitle.cs
@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Controller.Entities
+{
+    public interface IHasOriginalTitle
+    {
+        string OriginalTitle { get; set; }
+    }
+}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index e99c11e87d..727f756f15 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -30,7 +30,6 @@ namespace MediaBrowser.Controller.Entities
         public string[] IncludeItemTypes { get; set; }
         public string[] ExcludeItemTypes { get; set; }
         public string[] Genres { get; set; }
-        public string[] AllGenres { get; set; }
 
         public bool? IsMissing { get; set; }
         public bool? IsUnaired { get; set; }
@@ -42,6 +41,7 @@ namespace MediaBrowser.Controller.Entities
         public string NameLessThan { get; set; }
 
         public string Person { get; set; }
+        public string[] PersonIds { get; set; }
         public string AdjacentTo { get; set; }
         public string[] PersonTypes { get; set; }
 
@@ -66,6 +66,7 @@ namespace MediaBrowser.Controller.Entities
         public bool? HasParentalRating { get; set; }
 
         public string[] Studios { get; set; }
+        public string[] StudioIds { get; set; }
         public ImageType[] ImageTypes { get; set; }
         public VideoType[] VideoTypes { get; set; }
         public int[] Years { get; set; }
@@ -80,13 +81,14 @@ namespace MediaBrowser.Controller.Entities
             MediaTypes = new string[] { };
             IncludeItemTypes = new string[] { };
             ExcludeItemTypes = new string[] { };
-            AllGenres = new string[] { };
             Genres = new string[] { };
             Studios = new string[] { };
+            StudioIds = new string[] { };
             ImageTypes = new ImageType[] { };
             VideoTypes = new VideoType[] { };
             Years = new int[] { };
             PersonTypes = new string[] { };
+            PersonIds = new string[] { };
         }
     }
 }
diff --git a/MediaBrowser.Controller/Entities/ItemImageInfo.cs b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
index 80aec64824..b36b818ffe 100644
--- a/MediaBrowser.Controller/Entities/ItemImageInfo.cs
+++ b/MediaBrowser.Controller/Entities/ItemImageInfo.cs
@@ -5,10 +5,22 @@ namespace MediaBrowser.Controller.Entities
 {
     public class ItemImageInfo
     {
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
         public string Path { get; set; }
 
+        /// <summary>
+        /// Gets or sets the type.
+        /// </summary>
+        /// <value>The type.</value>
         public ImageType Type { get; set; }
 
+        /// <summary>
+        /// Gets or sets the date modified.
+        /// </summary>
+        /// <value>The date modified.</value>
         public DateTime DateModified { get; set; }
     }
 }
diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs
index 78e8e49594..949c9741b1 100644
--- a/MediaBrowser.Controller/Entities/LinkedChild.cs
+++ b/MediaBrowser.Controller/Entities/LinkedChild.cs
@@ -11,7 +11,6 @@ namespace MediaBrowser.Controller.Entities
 
         public string ItemName { get; set; }
         public string ItemType { get; set; }
-        public int? ItemYear { get; set; }
 
         [IgnoreDataMember]
         public string Id { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index cfe008bd7c..4110047821 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -6,7 +6,6 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using System.Runtime.Serialization;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -15,10 +14,11 @@ namespace MediaBrowser.Controller.Entities.Movies
     /// <summary>
     /// Class Movie
     /// </summary>
-    public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
+    public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasSpecialFeatures, IHasProductionLocations, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping, IHasOriginalTitle
     {
         public List<Guid> SpecialFeatureIds { get; set; }
 
+        public string OriginalTitle { get; set; }
         public List<Guid> SoundtrackIds { get; set; }
 
         public List<Guid> ThemeSongIds { get; set; }
diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs
index 771c62fd6d..b2cad02de8 100644
--- a/MediaBrowser.Controller/Entities/MusicVideo.cs
+++ b/MediaBrowser.Controller/Entities/MusicVideo.cs
@@ -47,16 +47,6 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        /// <summary>
-        /// Determines whether the specified name has artist.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <returns><c>true</c> if the specified name has artist; otherwise, <c>false</c>.</returns>
-        public bool HasArtist(string name)
-        {
-            return AllArtists.Contains(name, StringComparer.OrdinalIgnoreCase);
-        }
-        
         /// <summary>
         /// Gets the user data key.
         /// </summary>
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 4c34460d7c..b4e1d9d6e5 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -15,11 +15,12 @@ namespace MediaBrowser.Controller.Entities.TV
     /// <summary>
     /// Class Series
     /// </summary>
-    public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures, IMetadataContainer
+    public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasDisplayOrder, IHasLookupInfo<SeriesInfo>, IHasSpecialFeatures, IMetadataContainer, IHasOriginalTitle
     {
         public List<Guid> SpecialFeatureIds { get; set; }
         public List<Guid> SoundtrackIds { get; set; }
 
+        public string OriginalTitle { get; set; }
         public int SeasonCount { get; set; }
 
         public int? AnimeSeriesIndex { get; set; }
@@ -260,7 +261,7 @@ namespace MediaBrowser.Controller.Entities.TV
                 progress.Report(percent * 100);
             }
 
-            await ProviderManager.RefreshMetadata(this, refreshOptions, cancellationToken).ConfigureAwait(false);
+            await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
 
             progress.Report(100);
         }
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 5f7ca3d3f4..9be30273a0 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.TV;
+using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using System;
@@ -15,7 +16,13 @@ namespace MediaBrowser.Controller.Entities
         public Guid? UserId { get; set; }
 
         public static ITVSeriesManager TVSeriesManager;
+        public static IPlaylistManager PlaylistManager;
 
+        public bool ContainsDynamicCategories(User user)
+        {
+            return true;
+        }
+        
         public override Task<QueryResult<BaseItem>> GetItems(InternalItemsQuery query)
         {
             var parent = this as Folder;
@@ -25,7 +32,7 @@ namespace MediaBrowser.Controller.Entities
                 parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
             }
 
-            return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager)
+            return new UserViewBuilder(UserViewManager, LiveTvManager, ChannelManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, CollectionManager, PlaylistManager)
                 .GetUserItems(parent, this, ViewType, query);
         }
 
@@ -45,6 +52,11 @@ namespace MediaBrowser.Controller.Entities
             return false;
         }
 
+        public override bool IsSaveLocalMetadataEnabled()
+        {
+            return true;
+        }
+
         public override IEnumerable<BaseItem> GetRecursiveChildren(User user, Func<BaseItem, bool> filter)
         {
             var result = GetItems(new InternalItemsQuery
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index 85c10c272a..0e602dabe2 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.TV;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Entities;
@@ -18,7 +18,6 @@ using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MoreLinq;
 
 namespace MediaBrowser.Controller.Entities
 {
@@ -32,8 +31,9 @@ namespace MediaBrowser.Controller.Entities
         private readonly IUserDataManager _userDataManager;
         private readonly ITVSeriesManager _tvSeriesManager;
         private readonly ICollectionManager _collectionManager;
+        private readonly IPlaylistManager _playlistManager;
 
-        public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager)
+        public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager, IPlaylistManager playlistManager)
         {
             _userViewManager = userViewManager;
             _liveTvManager = liveTvManager;
@@ -43,6 +43,7 @@ namespace MediaBrowser.Controller.Entities
             _userDataManager = userDataManager;
             _tvSeriesManager = tvSeriesManager;
             _collectionManager = collectionManager;
+            _playlistManager = playlistManager;
         }
 
         public async Task<QueryResult<BaseItem>> GetUserItems(Folder queryParent, Folder displayParent, string viewType, InternalItemsQuery query)
@@ -111,12 +112,21 @@ namespace MediaBrowser.Controller.Entities
                         return GetResult(result, queryParent, query);
                     }
 
+                case CollectionType.Books:
+                case CollectionType.Photos:
+                case CollectionType.HomeVideos:
+                case CollectionType.MusicVideos:
+                    return GetResult(queryParent.GetChildren(user, true), queryParent, query);
+
                 case CollectionType.Folders:
                     return GetResult(user.RootFolder.GetChildren(user, true), queryParent, query);
 
                 case CollectionType.Games:
                     return await GetGameView(user, queryParent, query).ConfigureAwait(false);
 
+                case CollectionType.Playlists:
+                    return await GetPlaylistsView(queryParent, user, query).ConfigureAwait(false);
+
                 case CollectionType.BoxSets:
                     return await GetBoxsetView(queryParent, user, query).ConfigureAwait(false);
 
@@ -574,6 +584,11 @@ namespace MediaBrowser.Controller.Entities
             return GetResult(items, queryParent, query);
         }
 
+        private async Task<QueryResult<BaseItem>> GetPlaylistsView(Folder parent, User user, InternalItemsQuery query)
+        {
+            return GetResult(_playlistManager.GetPlaylists(user.Id.ToString("N")), parent, query);
+        }
+
         private async Task<QueryResult<BaseItem>> GetBoxsetView(Folder parent, User user, InternalItemsQuery query)
         {
             return GetResult(GetMediaFolders(user).SelectMany(i =>
@@ -937,11 +952,6 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
-            if (request.AllGenres.Length > 0)
-            {
-                return false;
-            }
-
             if (request.Genres.Length > 0)
             {
                 return false;
@@ -1047,11 +1057,21 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
+            if (request.PersonIds.Length > 0)
+            {
+                return false;
+            }
+
             if (request.Studios.Length > 0)
             {
                 return false;
             }
 
+            if (request.StudioIds.Length > 0)
+            {
+                return false;
+            }
+
             if (request.VideoTypes.Length > 0)
             {
                 return false;
@@ -1571,12 +1591,6 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
-            // Apply genre filter
-            if (query.AllGenres.Length > 0 && !query.AllGenres.All(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
-            {
-                return false;
-            }
-
             // Filter by VideoType
             if (query.VideoTypes.Length > 0)
             {
@@ -1598,6 +1612,16 @@ namespace MediaBrowser.Controller.Entities
                 return false;
             }
 
+            // Apply studio filter
+            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
+            {
+                var studioItem = libraryManager.GetItemById(id);
+                return studioItem != null && item.Studios.Contains(studioItem.Name, StringComparer.OrdinalIgnoreCase);
+            }))
+            {
+                return false;
+            }
+
             // Apply year filter
             if (query.Years.Length > 0)
             {
@@ -1614,7 +1638,22 @@ namespace MediaBrowser.Controller.Entities
             }
 
             // Apply person filter
-            if (!string.IsNullOrEmpty(query.Person))
+            if (query.PersonIds.Length > 0)
+            {
+                var names = query.PersonIds
+                    .Select(libraryManager.GetItemById)
+                    .Select(i => i == null ? "-1" : i.Name)
+                    .ToList();
+
+                if (!(names.Any(
+                        v => item.People.Select(i => i.Name).Contains(v, StringComparer.OrdinalIgnoreCase))))
+                {
+                    return false;
+                }
+            }
+
+            // Apply person filter
+            if (!string.IsNullOrWhiteSpace(query.Person))
             {
                 var personTypes = query.PersonTypes;
 
@@ -1716,7 +1755,7 @@ namespace MediaBrowser.Controller.Entities
 
             var parent = user.RootFolder;
 
-            //list.Add(await GetUserView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
+            //list.Add(await GetUserSubView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
             list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, parent).ConfigureAwait(false));
             list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, parent).ConfigureAwait(false));
 
@@ -1725,7 +1764,7 @@ namespace MediaBrowser.Controller.Entities
 
         private async Task<UserView> GetUserView(string name, string type, User user, string sortName, BaseItem parent)
         {
-            var view = await _userViewManager.GetUserView(name, parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
+            var view = await _userViewManager.GetUserSubView(name, parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
                         .ConfigureAwait(false);
 
             return view;
@@ -1733,7 +1772,7 @@ namespace MediaBrowser.Controller.Entities
 
         private async Task<UserView> GetUserView(string type, User user, string sortName, BaseItem parent)
         {
-            var view = await _userViewManager.GetUserView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
+            var view = await _userViewManager.GetUserSubView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
                         .ConfigureAwait(false);
 
             return view;
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index d4507bc337..ba84beca34 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -24,7 +24,8 @@ namespace MediaBrowser.Controller.Entities
         IHasMediaSources,
         IHasShortOverview,
         IHasPreferredMetadataLanguage,
-        IThemeMedia
+        IThemeMedia,
+        IArchivable
     {
         public Guid? PrimaryVersionId { get; set; }
 
@@ -420,12 +421,17 @@ namespace MediaBrowser.Controller.Entities
             return base.GetDeletePaths();
         }
 
-        public virtual IEnumerable<MediaStream> GetMediaStreams()
+        public IEnumerable<MediaStream> GetMediaStreams()
         {
-            return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
+            var mediaSource = GetMediaSources(false)
+                .FirstOrDefault();
+
+            if (mediaSource == null)
             {
-                ItemId = Id
-            });
+                return new List<MediaStream>();
+            }
+
+            return mediaSource.MediaStreams;
         }
 
         public virtual MediaStream GetDefaultVideoStream()
@@ -455,7 +461,7 @@ namespace MediaBrowser.Controller.Entities
 
             return result.OrderBy(i =>
             {
-                if (item.VideoType == VideoType.VideoFile)
+                if (i.VideoType == VideoType.VideoFile)
                 {
                     return 0;
                 }
@@ -474,7 +480,7 @@ namespace MediaBrowser.Controller.Entities
 
         private static MediaSourceInfo GetVersionInfo(bool enablePathSubstitution, Video i, MediaSourceType type)
         {
-            var mediaStreams = MediaSourceManager.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id })
+            var mediaStreams = MediaSourceManager.GetMediaStreams(i.Id)
                 .ToList();
 
             var locationType = i.LocationType;
@@ -551,7 +557,6 @@ namespace MediaBrowser.Controller.Entities
             return info;
         }
 
-
         private static string GetMediaSourceName(Video video, List<MediaStream> mediaStreams)
         {
             var terms = new List<string>();
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 9c8ed45a53..d16589f07f 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -302,7 +302,7 @@ namespace MediaBrowser.Controller.Library
         IEnumerable<BaseItem> ReplaceVideosWithPrimaryVersions(IEnumerable<BaseItem> items);
 
         /// <summary>
-        /// Gets the special folder.
+        /// Gets the named view.
         /// </summary>
         /// <param name="user">The user.</param>
         /// <param name="name">The name.</param>
@@ -311,7 +311,7 @@ namespace MediaBrowser.Controller.Library
         /// <param name="sortName">Name of the sort.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;UserView&gt;.</returns>
-        Task<UserView> GetSpecialFolder(User user,
+        Task<UserView> GetNamedView(User user,
             string name,
             string parentId,
             string viewType, 
@@ -321,12 +321,14 @@ namespace MediaBrowser.Controller.Library
         /// <summary>
         /// Gets the named view.
         /// </summary>
+        /// <param name="user">The user.</param>
         /// <param name="name">The name.</param>
         /// <param name="viewType">Type of the view.</param>
         /// <param name="sortName">Name of the sort.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;UserView&gt;.</returns>
-        Task<UserView> GetNamedView(string name, 
+        Task<UserView> GetNamedView(User user,
+            string name, 
             string viewType, 
             string sortName, 
             CancellationToken cancellationToken);
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index 4378bc85d9..c21fed6fc5 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -1,11 +1,76 @@
-using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using System;
 using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.Library
 {
     public interface IMediaSourceManager
     {
+        /// <summary>
+        /// Adds the parts.
+        /// </summary>
+        /// <param name="providers">The providers.</param>
+        void AddParts(IEnumerable<IMediaSourceProvider> providers);
+
+        /// <summary>
+        /// Gets the media streams.
+        /// </summary>
+        /// <param name="itemId">The item identifier.</param>
+        /// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
+        IEnumerable<MediaStream> GetMediaStreams(Guid itemId);
+        /// <summary>
+        /// Gets the media streams.
+        /// </summary>
+        /// <param name="mediaSourceId">The media source identifier.</param>
+        /// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
+        IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId);
+        /// <summary>
+        /// Gets the media streams.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
         IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query);
+
+        /// <summary>
+        /// Gets the playack media sources.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="userId">The user identifier.</param>
+        /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
+        Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the playack media sources.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
+        Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the static media sources.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+        /// <param name="user">The user.</param>
+        /// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
+        IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user);
+
+        /// <summary>
+        /// Gets the static media source.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="mediaSourceId">The media source identifier.</param>
+        /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+        /// <returns>MediaSourceInfo.</returns>
+        MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
     }
 }
diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
new file mode 100644
index 0000000000..461285d6cc
--- /dev/null
+++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
@@ -0,0 +1,19 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Dto;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Library
+{
+    public interface IMediaSourceProvider
+    {
+        /// <summary>
+        /// Gets the media sources.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
+        Task<IEnumerable<MediaSourceInfo>> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
+    }
+}
diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs
index 8119e5afbb..a167cdbed0 100644
--- a/MediaBrowser.Controller/Library/IUserManager.cs
+++ b/MediaBrowser.Controller/Library/IUserManager.cs
@@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.Library
         event EventHandler<GenericEventArgs<User>> UserCreated;
         event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
         event EventHandler<GenericEventArgs<User>> UserPasswordChanged;
+        event EventHandler<GenericEventArgs<User>> UserLockedOut;
 
         /// <summary>
         /// Gets a User by Id
diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs
index f55c179248..f0b862c2d2 100644
--- a/MediaBrowser.Controller/Library/IUserViewManager.cs
+++ b/MediaBrowser.Controller/Library/IUserViewManager.cs
@@ -12,12 +12,10 @@ namespace MediaBrowser.Controller.Library
     {
         Task<IEnumerable<Folder>> GetUserViews(UserViewQuery query, CancellationToken cancellationToken);
 
-        Task<UserView> GetUserView(string name, string parentId, string type, User user, string sortName,
+        Task<UserView> GetUserSubView(string name, string parentId, string type, User user, string sortName,
             CancellationToken cancellationToken);
 
-        Task<UserView> GetUserView(string type, string sortName, CancellationToken cancellationToken);
-
-        Task<UserView> GetUserView(string category, string type, User user, string sortName, CancellationToken cancellationToken);
+        Task<UserView> GetUserSubView(string category, string type, User user, string sortName, CancellationToken cancellationToken);
 
         List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request);
     }
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs b/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs
new file mode 100644
index 0000000000..d3334e8ea0
--- /dev/null
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs
@@ -0,0 +1,8 @@
+
+namespace MediaBrowser.Controller.LiveTv
+{
+    public interface ILiveTvItem
+    {
+        string ServiceName { get; set; }
+    }
+}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
index fcd973ec29..9b36454d2a 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs
@@ -14,12 +14,6 @@ namespace MediaBrowser.Controller.LiveTv
     /// </summary>
     public interface ILiveTvManager
     {
-        /// <summary>
-        /// Gets the active service.
-        /// </summary>
-        /// <value>The active service.</value>
-        ILiveTvService ActiveService { get; }
-
         /// <summary>
         /// Gets the services.
         /// </summary>
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
index 784cb6ea18..93e1e576ac 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs
@@ -1,4 +1,5 @@
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Library;
 using System.Threading;
@@ -6,10 +7,8 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.LiveTv
 {
-    public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData
+    public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData, ILiveTvItem
     {
-        string ServiceName { get; set; }
-
         string MediaType { get; }
 
         string Container { get; }
@@ -22,7 +21,7 @@ namespace MediaBrowser.Controller.LiveTv
 
         bool IsParentalAllowed(User user);
 
-        Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken);
+        Task<ItemUpdateType> RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken);
 
         PlayAccess GetPlayAccess(User user);
 
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index eaea6cfa45..75e418bcc9 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -11,7 +11,7 @@ using System.Runtime.Serialization;
 
 namespace MediaBrowser.Controller.LiveTv
 {
-    public class LiveTvChannel : BaseItem, IHasMediaSources
+    public class LiveTvChannel : BaseItem, IHasMediaSources, ILiveTvItem
     {
         /// <summary>
         /// Gets the user data key.
@@ -58,6 +58,10 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value>The type of the channel.</value>
         public ChannelType ChannelType { get; set; }
 
+        /// <summary>
+        /// Gets or sets the name of the service.
+        /// </summary>
+        /// <value>The name of the service.</value>
         public string ServiceName { get; set; }
 
         /// <summary>
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
index ee85ce20b0..0b07d8b6d1 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs
@@ -1,5 +1,6 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.Users;
@@ -11,7 +12,7 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.LiveTv
 {
-    public class LiveTvProgram : BaseItem
+    public class LiveTvProgram : BaseItem, ILiveTvItem, IHasLookupInfo<LiveTvProgramLookupInfo>
     {
         /// <summary>
         /// Gets the user data key.
@@ -220,5 +221,23 @@ namespace MediaBrowser.Controller.LiveTv
         {
             return false;
         }
+
+        public override bool IsInternetMetadataEnabled()
+        {
+            if (IsMovie)
+            {
+                var options = (LiveTvOptions)ConfigurationManager.GetConfiguration("livetv");
+                return options.EnableMovieProviders;
+            }
+
+            return false;
+        }
+
+        public LiveTvProgramLookupInfo GetLookupInfo()
+        {
+            var info = GetItemLookupInfo<LiveTvProgramLookupInfo>();
+            info.IsMovie = IsMovie; 
+            return info;
+        }
     }
 }
diff --git a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
index 4d7e5ee63e..36f082b02c 100644
--- a/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ProgramInfo.cs
@@ -145,6 +145,12 @@ namespace MediaBrowser.Controller.LiveTv
         /// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
         public bool IsPremiere { get; set;  }
 
+        /// <summary>
+        /// Gets or sets the production year.
+        /// </summary>
+        /// <value>The production year.</value>
+        public int? ProductionYear { get; set; }
+        
         public ProgramInfo()
         {
             Genres = new List<string>();
diff --git a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs
index d7250d9d2f..175cf162b4 100644
--- a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs
+++ b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs
@@ -1,5 +1,4 @@
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Users;
 
 namespace MediaBrowser.Controller.LiveTv
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index e9531e0571..e4a31c82d2 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -99,11 +99,13 @@
     <Compile Include="Collections\CollectionCreationOptions.cs" />
     <Compile Include="Collections\CollectionEvents.cs" />
     <Compile Include="Collections\ICollectionManager.cs" />
+    <Compile Include="Connect\ConnectSupporterSummary.cs" />
     <Compile Include="Connect\IConnectManager.cs" />
     <Compile Include="Connect\UserLinkResult.cs" />
     <Compile Include="Devices\CameraImageUploadInfo.cs" />
     <Compile Include="Devices\IDeviceManager.cs" />
     <Compile Include="Devices\IDeviceRepository.cs" />
+    <Compile Include="Diagnostics\IProcessManager.cs" />
     <Compile Include="Dlna\ControlRequest.cs" />
     <Compile Include="Dlna\ControlResponse.cs" />
     <Compile Include="Dlna\EventSubscriptionResponse.cs" />
@@ -129,6 +131,7 @@
     <Compile Include="Entities\Game.cs" />
     <Compile Include="Entities\GameGenre.cs" />
     <Compile Include="Entities\GameSystem.cs" />
+    <Compile Include="Entities\IArchivable.cs" />
     <Compile Include="Entities\IByReferenceItem.cs" />
     <Compile Include="Entities\IHasAspectRatio.cs" />
     <Compile Include="Entities\IHasBudget.cs" />
@@ -138,6 +141,7 @@
     <Compile Include="Entities\IHasKeywords.cs" />
     <Compile Include="Entities\IHasMediaSources.cs" />
     <Compile Include="Entities\IHasMetascore.cs" />
+    <Compile Include="Entities\IHasOriginalTitle.cs" />
     <Compile Include="Entities\IHasPreferredMetadataLanguage.cs" />
     <Compile Include="Entities\IHasProductionLocations.cs" />
     <Compile Include="Entities\IHasScreenshots.cs" />
@@ -171,6 +175,7 @@
     <Compile Include="Library\DeleteOptions.cs" />
     <Compile Include="Library\ILibraryPostScanTask.cs" />
     <Compile Include="Library\IMediaSourceManager.cs" />
+    <Compile Include="Library\IMediaSourceProvider.cs" />
     <Compile Include="Library\IMetadataFileSaver.cs" />
     <Compile Include="Library\IMetadataSaver.cs" />
     <Compile Include="Library\IMusicManager.cs" />
@@ -182,6 +187,7 @@
     <Compile Include="Library\MetadataConfigurationStore.cs" />
     <Compile Include="Library\PlaybackStopEventArgs.cs" />
     <Compile Include="Library\UserDataSaveEventArgs.cs" />
+    <Compile Include="LiveTv\ILiveTvItem.cs" />
     <Compile Include="LiveTv\RecordingGroup.cs" />
     <Compile Include="LiveTv\RecordingStatusChangedEventArgs.cs" />
     <Compile Include="LiveTv\ILiveTvRecording.cs" />
@@ -243,22 +249,69 @@
     <Compile Include="Persistence\MediaStreamQuery.cs" />
     <Compile Include="Playlists\IPlaylistManager.cs" />
     <Compile Include="Playlists\Playlist.cs" />
+    <Compile Include="Plugins\ILocalizablePlugin.cs" />
+    <Compile Include="Providers\AlbumInfo.cs" />
+    <Compile Include="Providers\ArtistInfo.cs" />
+    <Compile Include="Providers\BookInfo.cs" />
+    <Compile Include="Providers\BoxSetInfo.cs" />
+    <Compile Include="Providers\ChannelItemLookupInfo.cs" />
     <Compile Include="Providers\DirectoryService.cs" />
+    <Compile Include="Providers\DynamicImageInfo.cs" />
+    <Compile Include="Providers\DynamicImageResponse.cs" />
+    <Compile Include="Providers\EpisodeIdentity.cs" />
+    <Compile Include="Providers\EpisodeInfo.cs" />
+    <Compile Include="Providers\ExtraInfo.cs" />
+    <Compile Include="Providers\ExtraSource.cs" />
+    <Compile Include="Providers\GameInfo.cs" />
+    <Compile Include="Providers\GameSystemInfo.cs" />
     <Compile Include="Providers\ICustomMetadataProvider.cs" />
+    <Compile Include="Providers\IDirectoryService.cs" />
+    <Compile Include="Providers\IDynamicImageProvider.cs" />
     <Compile Include="Providers\IExternalId.cs" />
     <Compile Include="Providers\IExtrasProvider.cs" />
     <Compile Include="Providers\IForcedProvider.cs" />
     <Compile Include="Providers\IHasChangeMonitor.cs" />
     <Compile Include="Entities\IHasMetadata.cs" />
+    <Compile Include="Providers\IHasIdentities.cs" />
+    <Compile Include="Providers\IHasItemChangeMonitor.cs" />
+    <Compile Include="Providers\IHasLookupInfo.cs" />
+    <Compile Include="Providers\IHasOrder.cs" />
+    <Compile Include="Providers\IImageFileSaver.cs" />
     <Compile Include="Providers\IImageProvider.cs" />
     <Compile Include="Providers\IImageSaver.cs" />
+    <Compile Include="Providers\IItemIdentity.cs" />
+    <Compile Include="Providers\IItemIdentityConverter.cs" />
+    <Compile Include="Providers\IItemIdentityProvider.cs" />
+    <Compile Include="Providers\ILocalImageFileProvider.cs" />
     <Compile Include="Providers\ILocalMetadataProvider.cs" />
+    <Compile Include="Providers\ImageRefreshMode.cs" />
+    <Compile Include="Providers\ImageRefreshOptions.cs" />
+    <Compile Include="Providers\IPreRefreshProvider.cs" />
     <Compile Include="Providers\IProviderRepository.cs" />
     <Compile Include="Providers\IRemoteImageProvider.cs" />
     <Compile Include="Providers\ILocalImageProvider.cs" />
     <Compile Include="Providers\IMetadataProvider.cs" />
     <Compile Include="Providers\IMetadataService.cs" />
     <Compile Include="Providers\IRemoteMetadataProvider.cs" />
+    <Compile Include="Providers\IRemoteSearchProvider.cs" />
+    <Compile Include="Providers\ISeriesOrderProvider.cs" />
+    <Compile Include="Providers\ItemInfo.cs" />
+    <Compile Include="Providers\LiveTvProgramLookupInfo.cs" />
+    <Compile Include="Providers\LocalImageInfo.cs" />
+    <Compile Include="Providers\LocalMetadataResult.cs" />
+    <Compile Include="Providers\MetadataRefreshMode.cs" />
+    <Compile Include="Providers\MetadataResult.cs" />
+    <Compile Include="Providers\MovieInfo.cs" />
+    <Compile Include="Providers\MusicVideoInfo.cs" />
+    <Compile Include="Providers\PersonLookupInfo.cs" />
+    <Compile Include="Providers\RemoteSearchQuery.cs" />
+    <Compile Include="Providers\SeasonIdentity.cs" />
+    <Compile Include="Providers\SeasonInfo.cs" />
+    <Compile Include="Providers\SeriesIdentity.cs" />
+    <Compile Include="Providers\SeriesInfo.cs" />
+    <Compile Include="Providers\SeriesOrderTypes.cs" />
+    <Compile Include="Providers\SongInfo.cs" />
+    <Compile Include="Providers\TrailerInfo.cs" />
     <Compile Include="Providers\VideoContentType.cs" />
     <Compile Include="RelatedMedia\IRelatedMediaProvider.cs" />
     <Compile Include="Security\AuthenticationInfo.cs" />
@@ -341,11 +394,12 @@
     <Compile Include="Subtitles\SubtitleDownloadEventArgs.cs" />
     <Compile Include="Subtitles\SubtitleResponse.cs" />
     <Compile Include="Subtitles\SubtitleSearchRequest.cs" />
-    <Compile Include="Sync\ICloudSyncProvider.cs" />
     <Compile Include="Sync\IServerSyncProvider.cs" />
+    <Compile Include="Sync\ISyncDataProvider.cs" />
     <Compile Include="Sync\ISyncManager.cs" />
     <Compile Include="Sync\ISyncProvider.cs" />
     <Compile Include="Sync\ISyncRepository.cs" />
+    <Compile Include="Sync\SendFileResult.cs" />
     <Compile Include="Themes\IAppThemeManager.cs" />
     <Compile Include="Themes\InternalThemeImage.cs" />
     <Compile Include="TV\ITVSeriesManager.cs" />
diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
index 990d23970a..0afaf955e9 100644
--- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
+++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
@@ -70,6 +70,11 @@ namespace MediaBrowser.Controller.Net
         /// <returns>Task.</returns>
         public Task ProcessMessage(WebSocketMessageInfo message)
         {
+            if (message == null)
+            {
+                throw new ArgumentNullException("message");
+            }
+
             if (message.MessageType.Equals(Name + "Start", StringComparison.OrdinalIgnoreCase))
             {
                 Start(message);
diff --git a/MediaBrowser.Controller/Net/IHttpServer.cs b/MediaBrowser.Controller/Net/IHttpServer.cs
index 315b48b837..37142af194 100644
--- a/MediaBrowser.Controller/Net/IHttpServer.cs
+++ b/MediaBrowser.Controller/Net/IHttpServer.cs
@@ -44,6 +44,11 @@ namespace MediaBrowser.Controller.Net
         /// </summary>
         event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
 
+        /// <summary>
+        /// Occurs when [web socket connecting].
+        /// </summary>
+        event EventHandler<WebSocketConnectingEventArgs> WebSocketConnecting;
+
         /// <summary>
         /// Inits this instance.
         /// </summary>
diff --git a/MediaBrowser.Controller/Net/IServerManager.cs b/MediaBrowser.Controller/Net/IServerManager.cs
index d90a0f8ed6..5191a62e31 100644
--- a/MediaBrowser.Controller/Net/IServerManager.cs
+++ b/MediaBrowser.Controller/Net/IServerManager.cs
@@ -1,4 +1,4 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Model.Events;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -58,5 +58,10 @@ namespace MediaBrowser.Controller.Net
         /// </summary>
         /// <value>The web socket connections.</value>
         IEnumerable<IWebSocketConnection> WebSocketConnections { get; }
+
+        /// <summary>
+        /// Occurs when [web socket connected].
+        /// </summary>
+        event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Net/ISessionContext.cs b/MediaBrowser.Controller/Net/ISessionContext.cs
index be8d28acc6..167e178671 100644
--- a/MediaBrowser.Controller/Net/ISessionContext.cs
+++ b/MediaBrowser.Controller/Net/ISessionContext.cs
@@ -1,14 +1,15 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Session;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.Net
 {
     public interface ISessionContext 
     {
-        SessionInfo GetSession(object requestContext);
-        User GetUser(object requestContext);
-   
-        SessionInfo GetSession(IServiceRequest requestContext);
-        User GetUser(IServiceRequest requestContext);
+        Task<SessionInfo> GetSession(object requestContext);
+        Task<User> GetUser(object requestContext);
+
+        Task<SessionInfo> GetSession(IServiceRequest requestContext);
+        Task<User> GetUser(IServiceRequest requestContext);
     }
 }
diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
index 37fd6708d9..e21df3c395 100644
--- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs
+++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs
@@ -1,5 +1,6 @@
 using MediaBrowser.Model.Net;
 using System;
+using System.Collections.Specialized;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -11,7 +12,7 @@ namespace MediaBrowser.Controller.Net
         /// Occurs when [closed].
         /// </summary>
         event EventHandler<EventArgs> Closed;
-        
+
         /// <summary>
         /// Gets the id.
         /// </summary>
@@ -24,6 +25,17 @@ namespace MediaBrowser.Controller.Net
         /// <value>The last activity date.</value>
         DateTime LastActivityDate { get; }
 
+        /// <summary>
+        /// Gets or sets the URL.
+        /// </summary>
+        /// <value>The URL.</value>
+        string Url { get; set; }
+        /// <summary>
+        /// Gets or sets the query string.
+        /// </summary>
+        /// <value>The query string.</value>
+        NameValueCollection QueryString { get; set; }
+
         /// <summary>
         /// Gets or sets the receive action.
         /// </summary>
diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs
index 5bb2c9a5c3..6a104554af 100644
--- a/MediaBrowser.Controller/Net/StaticResultOptions.cs
+++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs
@@ -18,11 +18,6 @@ namespace MediaBrowser.Controller.Net
 
         public IDictionary<string, string> ResponseHeaders { get; set; }
 
-        public bool Throttle { get; set; }
-        public long ThrottleLimit { get; set; }
-        public long MinThrottlePosition { get; set; }
-        public Func<long, long, long> ThrottleCallback { get; set; }
-
         public Action OnComplete { get; set; }
 
         public StaticResultOptions()
diff --git a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs
index 394fcd92ff..ffeaf286e2 100644
--- a/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs
+++ b/MediaBrowser.Controller/Net/WebSocketConnectEventArgs.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Specialized;
 
 namespace MediaBrowser.Controller.Net
 {
@@ -7,6 +8,16 @@ namespace MediaBrowser.Controller.Net
     /// </summary>
     public class WebSocketConnectEventArgs : EventArgs
     {
+        /// <summary>
+        /// Gets or sets the URL.
+        /// </summary>
+        /// <value>The URL.</value>
+        public string Url { get; set; }
+        /// <summary>
+        /// Gets or sets the query string.
+        /// </summary>
+        /// <value>The query string.</value>
+        public NameValueCollection QueryString { get; set; }
         /// <summary>
         /// Gets or sets the web socket.
         /// </summary>
@@ -18,4 +29,35 @@ namespace MediaBrowser.Controller.Net
         /// <value>The endpoint.</value>
         public string Endpoint { get; set; }
     }
+
+    public class WebSocketConnectingEventArgs : EventArgs
+    {
+        /// <summary>
+        /// Gets or sets the URL.
+        /// </summary>
+        /// <value>The URL.</value>
+        public string Url { get; set; }
+        /// <summary>
+        /// Gets or sets the endpoint.
+        /// </summary>
+        /// <value>The endpoint.</value>
+        public string Endpoint { get; set; }
+        /// <summary>
+        /// Gets or sets the query string.
+        /// </summary>
+        /// <value>The query string.</value>
+        public NameValueCollection QueryString { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether [allow connection].
+        /// </summary>
+        /// <value><c>true</c> if [allow connection]; otherwise, <c>false</c>.</value>
+        public bool AllowConnection { get; set; }
+
+        public WebSocketConnectingEventArgs()
+        {
+            QueryString = new NameValueCollection();
+            AllowConnection = true;
+        }
+    }
+
 }
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index 3479902cbd..fdc36db354 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -106,7 +106,7 @@ namespace MediaBrowser.Controller.Playlists
                 Func<BaseItem, bool> filter = i =>
                 {
                     var audio = i as Audio;
-                    return audio != null && audio.HasArtist(musicArtist.Name);
+                    return audio != null && audio.HasAnyArtist(musicArtist.Name);
                 };
 
                 var items = user == null
diff --git a/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs b/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs
new file mode 100644
index 0000000000..d294107d74
--- /dev/null
+++ b/MediaBrowser.Controller/Plugins/ILocalizablePlugin.cs
@@ -0,0 +1,20 @@
+using System.IO;
+using System.Reflection;
+
+namespace MediaBrowser.Controller.Plugins
+{
+    public interface ILocalizablePlugin
+    {
+        Stream GetDictionary(string culture);
+    }
+
+    public static class LocalizablePluginHelper
+    {
+        public static Stream GetDictionary(Assembly assembly, string manifestPrefix, string culture)
+        {
+            // Find all dictionaries using GetManifestResourceNames, start start with the prefix
+            // Return the one for the culture if exists, otherwise return the default
+            return null;
+        } 
+    }
+}
diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs
new file mode 100644
index 0000000000..b884774094
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class AlbumInfo : ItemLookupInfo
+    {
+        /// <summary>
+        /// Gets or sets the album artist.
+        /// </summary>
+        /// <value>The album artist.</value>
+        public List<string> AlbumArtists { get; set; }
+
+        /// <summary>
+        /// Gets or sets the artist provider ids.
+        /// </summary>
+        /// <value>The artist provider ids.</value>
+        public Dictionary<string, string> ArtistProviderIds { get; set; }
+        public List<SongInfo> SongInfos { get; set; }
+
+        public AlbumInfo()
+        {
+            ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+            SongInfos = new List<SongInfo>();
+            AlbumArtists = new List<string>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ArtistInfo.cs b/MediaBrowser.Controller/Providers/ArtistInfo.cs
new file mode 100644
index 0000000000..8a4abd5c68
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ArtistInfo.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ArtistInfo : ItemLookupInfo
+    {
+        public List<SongInfo> SongInfos { get; set; }
+
+        public ArtistInfo()
+        {
+            SongInfos = new List<SongInfo>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
index a22e492f47..6facc1074a 100644
--- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
+++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
@@ -126,6 +126,21 @@ namespace MediaBrowser.Controller.Providers
                         break;
                     }
 
+                case "OriginalTitle":
+                    {
+                        var val = reader.ReadElementContentAsString();
+
+                        var hasOriginalTitle = item as IHasOriginalTitle;
+                        if (hasOriginalTitle != null)
+                        {
+                            if (!string.IsNullOrEmpty(hasOriginalTitle.OriginalTitle))
+                            {
+                                hasOriginalTitle.OriginalTitle = val;
+                            }
+                        }
+                        break;
+                    }
+
                 case "LocalTitle":
                     item.Name = reader.ReadElementContentAsString();
                     break;
@@ -1407,23 +1422,6 @@ namespace MediaBrowser.Controller.Providers
                                 break;
                             }
 
-                        case "Year":
-                            {
-                                var val = reader.ReadElementContentAsString();
-
-                                if (!string.IsNullOrWhiteSpace(val))
-                                {
-                                    int rval;
-
-                                    if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval))
-                                    {
-                                        linkedItem.ItemYear = rval;
-                                    }
-                                }
-
-                                break;
-                            }
-
                         default:
                             reader.Skip();
                             break;
diff --git a/MediaBrowser.Controller/Providers/BookInfo.cs b/MediaBrowser.Controller/Providers/BookInfo.cs
new file mode 100644
index 0000000000..52519bcb04
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/BookInfo.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class BookInfo : ItemLookupInfo
+    {
+        public string SeriesName { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/BoxSetInfo.cs b/MediaBrowser.Controller/Providers/BoxSetInfo.cs
new file mode 100644
index 0000000000..f604231de4
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/BoxSetInfo.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class BoxSetInfo : ItemLookupInfo
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ChannelItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ChannelItemLookupInfo.cs
new file mode 100644
index 0000000000..6c972f3bf5
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ChannelItemLookupInfo.cs
@@ -0,0 +1,11 @@
+using MediaBrowser.Model.Channels;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ChannelItemLookupInfo : ItemLookupInfo
+    {
+        public ChannelMediaContentType ContentType { get; set; }
+        public ExtraType ExtraType { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs
index 06ea7be02d..9e549dcf3f 100644
--- a/MediaBrowser.Controller/Providers/DirectoryService.cs
+++ b/MediaBrowser.Controller/Providers/DirectoryService.cs
@@ -7,16 +7,6 @@ using System.Linq;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public interface IDirectoryService
-    {
-        IEnumerable<FileSystemInfo> GetFileSystemEntries(string path);
-        IEnumerable<FileSystemInfo> GetFiles(string path);
-        IEnumerable<FileSystemInfo> GetDirectories(string path);
-        IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache);
-        FileSystemInfo GetFile(string path);
-        Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path);
-    }
-
     public class DirectoryService : IDirectoryService
     {
         private readonly ILogger _logger;
diff --git a/MediaBrowser.Controller/Providers/DynamicImageInfo.cs b/MediaBrowser.Controller/Providers/DynamicImageInfo.cs
new file mode 100644
index 0000000000..14b4c6afbe
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/DynamicImageInfo.cs
@@ -0,0 +1,10 @@
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class DynamicImageInfo
+    {
+        public string ImageId { get; set; }
+        public ImageType Type { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
new file mode 100644
index 0000000000..71a937cd9d
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+using MediaBrowser.Model.Drawing;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class DynamicImageResponse
+    {
+        public string Path { get; set; }
+        public Stream Stream { get; set; }
+        public ImageFormat Format { get; set; }
+        public bool HasImage { get; set; }
+        public string InternalCacheKey { get; set; }
+
+        public void SetFormatFromMimeType(string mimeType)
+        {
+            if (mimeType.EndsWith("gif", StringComparison.OrdinalIgnoreCase))
+            {
+                Format = ImageFormat.Gif;
+            }
+            else if (mimeType.EndsWith("bmp", StringComparison.OrdinalIgnoreCase))
+            {
+                Format = ImageFormat.Bmp;
+            }
+            else if (mimeType.EndsWith("png", StringComparison.OrdinalIgnoreCase))
+            {
+                Format = ImageFormat.Png;
+            }
+            else
+            {
+                Format = ImageFormat.Jpg;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/EpisodeIdentity.cs b/MediaBrowser.Controller/Providers/EpisodeIdentity.cs
new file mode 100644
index 0000000000..53f469e955
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/EpisodeIdentity.cs
@@ -0,0 +1,12 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class EpisodeIdentity : IItemIdentity
+    {
+        public string Type { get; set; }
+
+        public string SeriesId { get; set; }
+        public int? SeasonIndex { get; set; }
+        public int IndexNumber { get; set; }
+        public int? IndexNumberEnd { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
new file mode 100644
index 0000000000..88a7cbab7f
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class EpisodeInfo : ItemLookupInfo, IHasIdentities<EpisodeIdentity>
+    {
+        private List<EpisodeIdentity> _identities = new List<EpisodeIdentity>();
+
+        public Dictionary<string, string> SeriesProviderIds { get; set; }
+
+        public int? IndexNumberEnd { get; set; }
+        public int? AnimeSeriesIndex { get; set; }
+
+        public EpisodeInfo()
+        {
+            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public IEnumerable<EpisodeIdentity> Identities
+        {
+            get { return _identities; }
+        }
+
+        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
+        {
+            var identifier = new ItemIdentifier<EpisodeInfo, EpisodeIdentity>();
+            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ExtraInfo.cs b/MediaBrowser.Controller/Providers/ExtraInfo.cs
new file mode 100644
index 0000000000..1fbe6e93aa
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ExtraInfo.cs
@@ -0,0 +1,15 @@
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ExtraInfo
+    {
+        public string Path { get; set; }
+
+        public LocationType LocationType { get; set; }
+
+        public bool IsDownloadable { get; set; }
+
+        public ExtraType ExtraType { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ExtraSource.cs b/MediaBrowser.Controller/Providers/ExtraSource.cs
new file mode 100644
index 0000000000..901af60f86
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ExtraSource.cs
@@ -0,0 +1,9 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public enum ExtraSource
+    {
+        Local = 1,
+        Metadata = 2,
+        Remote = 3
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/GameInfo.cs b/MediaBrowser.Controller/Providers/GameInfo.cs
new file mode 100644
index 0000000000..771cf6cecb
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/GameInfo.cs
@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class GameInfo : ItemLookupInfo
+    {
+        /// <summary>
+        /// Gets or sets the game system.
+        /// </summary>
+        /// <value>The game system.</value>
+        public string GameSystem { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/GameSystemInfo.cs b/MediaBrowser.Controller/Providers/GameSystemInfo.cs
new file mode 100644
index 0000000000..efe2635cd3
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/GameSystemInfo.cs
@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class GameSystemInfo : ItemLookupInfo
+    {
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
+        public string Path { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs
index 3ce6ac46b9..c9393f4c36 100644
--- a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs
@@ -21,9 +21,4 @@ namespace MediaBrowser.Controller.Providers
         /// <returns>Task{ItemUpdateType}.</returns>
         Task<ItemUpdateType> FetchAsync(TItemType item, MetadataRefreshOptions options, CancellationToken cancellationToken);
     }
-
-    public interface IPreRefreshProvider : ICustomMetadataProvider
-    {
-        
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs
new file mode 100644
index 0000000000..343cf361f0
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IDirectoryService
+    {
+        IEnumerable<FileSystemInfo> GetFileSystemEntries(string path);
+        IEnumerable<FileSystemInfo> GetFiles(string path);
+        IEnumerable<FileSystemInfo> GetDirectories(string path);
+        IEnumerable<FileSystemInfo> GetFiles(string path, bool clearCache);
+        FileSystemInfo GetFile(string path);
+        Dictionary<string, FileSystemInfo> GetFileSystemDictionary(string path);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs b/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs
new file mode 100644
index 0000000000..9c3f947637
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IDynamicImageProvider.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IDynamicImageProvider : IImageProvider
+    {
+        /// <summary>
+        /// Gets the supported images.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <returns>IEnumerable{ImageType}.</returns>
+        IEnumerable<ImageType> GetSupportedImages(IHasImages item);
+
+        /// <summary>
+        /// Gets the image.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{DynamicImageResponse}.</returns>
+        Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IExtrasProvider.cs b/MediaBrowser.Controller/Providers/IExtrasProvider.cs
index 953bf02a11..3b72232c21 100644
--- a/MediaBrowser.Controller/Providers/IExtrasProvider.cs
+++ b/MediaBrowser.Controller/Providers/IExtrasProvider.cs
@@ -1,5 +1,4 @@
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Controller.Providers
 {
@@ -18,22 +17,4 @@ namespace MediaBrowser.Controller.Providers
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         bool Supports(IHasMetadata item);
     }
-
-    public enum ExtraSource
-    {
-        Local = 1,
-        Metadata = 2,
-        Remote = 3
-    }
-
-    public class ExtraInfo
-    {
-        public string Path { get; set; }
-
-        public LocationType LocationType { get; set; }
-
-        public bool IsDownloadable { get; set; }
-
-        public ExtraType ExtraType { get; set; }
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs b/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs
index d914abf618..aa0b0e3c97 100644
--- a/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs
+++ b/MediaBrowser.Controller/Providers/IHasChangeMonitor.cs
@@ -14,16 +14,4 @@ namespace MediaBrowser.Controller.Providers
         /// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
         bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date);
     }
-
-    public interface IHasItemChangeMonitor
-    {
-        /// <summary>
-        /// Determines whether the specified item has changed.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="status">The status.</param>
-        /// <param name="directoryService">The directory service.</param>
-        /// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
-        bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService);
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IHasIdentities.cs b/MediaBrowser.Controller/Providers/IHasIdentities.cs
new file mode 100644
index 0000000000..36f940dd31
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IHasIdentities.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasIdentities<out TIdentity>
+        where TIdentity : IItemIdentity
+    {
+        IEnumerable<TIdentity> Identities { get; }
+
+        Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs b/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs
new file mode 100644
index 0000000000..4c7069dd6d
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IHasItemChangeMonitor.cs
@@ -0,0 +1,16 @@
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasItemChangeMonitor
+    {
+        /// <summary>
+        /// Determines whether the specified item has changed.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="status">The status.</param>
+        /// <param name="directoryService">The directory service.</param>
+        /// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
+        bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IHasLookupInfo.cs b/MediaBrowser.Controller/Providers/IHasLookupInfo.cs
new file mode 100644
index 0000000000..afce498526
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IHasLookupInfo.cs
@@ -0,0 +1,8 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasLookupInfo<out TLookupInfoType>
+        where TLookupInfoType : ItemLookupInfo, new()
+    {
+        TLookupInfoType GetLookupInfo();
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IHasOrder.cs b/MediaBrowser.Controller/Providers/IHasOrder.cs
new file mode 100644
index 0000000000..cb5298dd36
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IHasOrder.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IHasOrder
+    {
+        int Order { get; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
index 56f8d02bef..e5a51a56e0 100644
--- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs
+++ b/MediaBrowser.Controller/Providers/IImageEnhancer.cs
@@ -44,11 +44,12 @@ namespace MediaBrowser.Controller.Providers
         /// Enhances the image async.
         /// </summary>
         /// <param name="item">The item.</param>
-        /// <param name="originalImage">The original image.</param>
+        /// <param name="inputFile">The input file.</param>
+        /// <param name="outputFile">The output file.</param>
         /// <param name="imageType">Type of the image.</param>
         /// <param name="imageIndex">Index of the image.</param>
         /// <returns>Task{Image}.</returns>
         /// <exception cref="System.ArgumentNullException"></exception>
-        Task<ImageStream> EnhanceImageAsync(IHasImages item, ImageStream originalImage, ImageType imageType, int imageIndex);
+        Task EnhanceImageAsync(IHasImages item, string inputFile, string outputFile, ImageType imageType, int imageIndex);
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IImageFileSaver.cs b/MediaBrowser.Controller/Providers/IImageFileSaver.cs
new file mode 100644
index 0000000000..3e11d8bf89
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IImageFileSaver.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IImageFileSaver : IImageSaver
+    {
+        /// <summary>
+        /// Gets the save paths.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="index">The index.</param>
+        /// <returns>IEnumerable{System.String}.</returns>
+        IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IImageSaver.cs b/MediaBrowser.Controller/Providers/IImageSaver.cs
index a983de63e7..62017160f4 100644
--- a/MediaBrowser.Controller/Providers/IImageSaver.cs
+++ b/MediaBrowser.Controller/Providers/IImageSaver.cs
@@ -1,9 +1,4 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Providers
+namespace MediaBrowser.Controller.Providers
 {
     public interface IImageSaver
     {
@@ -13,17 +8,4 @@ namespace MediaBrowser.Controller.Providers
         /// <value>The name.</value>
         string Name { get; }
     }
-
-    public interface IImageFileSaver : IImageSaver
-    {
-        /// <summary>
-        /// Gets the save paths.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="format">The format.</param>
-        /// <param name="index">The index.</param>
-        /// <returns>IEnumerable{System.String}.</returns>
-        IEnumerable<string> GetSavePaths(IHasImages item, ImageType type, ImageFormat format, int index);
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IItemIdentity.cs b/MediaBrowser.Controller/Providers/IItemIdentity.cs
new file mode 100644
index 0000000000..cab189c84f
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IItemIdentity.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IItemIdentity
+    {
+        string Type { get; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs b/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
new file mode 100644
index 0000000000..30e96b9e51
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IItemIdentityConverter.cs
@@ -0,0 +1,4 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IItemIdentityConverter : IHasOrder { }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs b/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
new file mode 100644
index 0000000000..9d437c208b
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IItemIdentityProvider.cs
@@ -0,0 +1,4 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IItemIdentityProvider : IHasOrder { }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs
new file mode 100644
index 0000000000..7e5d828437
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface ILocalImageFileProvider : ILocalImageProvider
+    {
+        List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs
index d1345d7a6e..1027a4cb27 100644
--- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs
+++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs
@@ -1,13 +1,4 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Controller.Providers
+namespace MediaBrowser.Controller.Providers
 {
     /// <summary>
     /// This is just a marker interface
@@ -15,68 +6,4 @@ namespace MediaBrowser.Controller.Providers
     public interface ILocalImageProvider : IImageProvider
     {
     }
-
-    public interface ILocalImageFileProvider : ILocalImageProvider
-    {
-        List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService);
-    }
-
-    public class LocalImageInfo
-    {
-        public FileSystemInfo FileInfo { get; set; }
-        public ImageType Type { get; set; }
-    }
-
-    public interface IDynamicImageProvider : IImageProvider
-    {
-        /// <summary>
-        /// Gets the supported images.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <returns>IEnumerable{ImageType}.</returns>
-        IEnumerable<ImageType> GetSupportedImages(IHasImages item);
-
-        /// <summary>
-        /// Gets the image.
-        /// </summary>
-        /// <param name="item">The item.</param>
-        /// <param name="type">The type.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{DynamicImageResponse}.</returns>
-        Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken);
-    }
-
-    public class DynamicImageInfo
-    {
-        public string ImageId { get; set; }
-        public ImageType Type { get; set; }
-    }
-
-    public class DynamicImageResponse
-    {
-        public string Path { get; set; }
-        public Stream Stream { get; set; }
-        public ImageFormat Format { get; set; }
-        public bool HasImage { get; set; }
-
-        public void SetFormatFromMimeType(string mimeType)
-        {
-            if (mimeType.EndsWith("gif", StringComparison.OrdinalIgnoreCase))
-            {
-                Format = ImageFormat.Gif;
-            }
-            else if (mimeType.EndsWith("bmp", StringComparison.OrdinalIgnoreCase))
-            {
-                Format = ImageFormat.Bmp;
-            }
-            else if (mimeType.EndsWith("png", StringComparison.OrdinalIgnoreCase))
-            {
-                Format = ImageFormat.Png;
-            }
-            else
-            {
-                Format = ImageFormat.Jpg;
-            }
-        }
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs b/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs
index 61bc3b87ba..3a8ef73254 100644
--- a/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs
@@ -1,6 +1,4 @@
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -24,29 +22,4 @@ namespace MediaBrowser.Controller.Providers
             IDirectoryService directoryService,
             CancellationToken cancellationToken);
     }
-
-    public class ItemInfo
-    {
-        public string Path { get; set; }
-
-        public bool IsInMixedFolder { get; set; }
-    }
-
-    public class LocalMetadataResult<T>
-        where T : IHasMetadata
-    {
-        public bool HasMetadata { get; set; }
-        public T Item { get; set; }
-        
-        public List<LocalImageInfo> Images { get; set; }
-        public List<ChapterInfo> Chapters { get; set; }
-        public List<UserItemData> UserDataLIst { get; set; }
-
-        public LocalMetadataResult()
-        {
-            Images = new List<LocalImageInfo>();
-            Chapters = new List<ChapterInfo>();
-            UserDataLIst = new List<UserItemData>();
-        }
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IMetadataProvider.cs b/MediaBrowser.Controller/Providers/IMetadataProvider.cs
index 52cd6fceac..26f43d820d 100644
--- a/MediaBrowser.Controller/Providers/IMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/IMetadataProvider.cs
@@ -19,15 +19,4 @@ namespace MediaBrowser.Controller.Providers
            where TItemType : IHasMetadata
     {
     }
-
-    public interface IHasOrder
-    {
-        int Order { get; }
-    }
-
-    public class MetadataResult<T>
-    {
-        public bool HasMetadata { get; set; }
-        public T Item { get; set; }
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IMetadataService.cs b/MediaBrowser.Controller/Providers/IMetadataService.cs
index 786a7147c2..2d4873f7ed 100644
--- a/MediaBrowser.Controller/Providers/IMetadataService.cs
+++ b/MediaBrowser.Controller/Providers/IMetadataService.cs
@@ -1,6 +1,7 @@
-using System.Threading;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Controller.Entities;
 
 namespace MediaBrowser.Controller.Providers
 {
@@ -20,7 +21,7 @@ namespace MediaBrowser.Controller.Providers
         /// <param name="refreshOptions">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken);
+        Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken);
 
         /// <summary>
         /// Gets the order.
diff --git a/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs b/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs
new file mode 100644
index 0000000000..6086749052
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IPreRefreshProvider : ICustomMetadataProvider
+    {
+        
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index 3cb745ff43..d40fa835fc 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Providers;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Threading;
@@ -16,6 +17,22 @@ namespace MediaBrowser.Controller.Providers
     /// </summary>
     public interface IProviderManager
     {
+        /// <summary>
+        /// Queues the refresh.
+        /// </summary>
+        /// <param name="itemId">The item identifier.</param>
+        /// <param name="options">The options.</param>
+        void QueueRefresh(Guid itemId, MetadataRefreshOptions options);
+
+        /// <summary>
+        /// Refreshes the full item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
+        
         /// <summary>
         /// Refreshes the metadata.
         /// </summary>
@@ -23,7 +40,7 @@ namespace MediaBrowser.Controller.Providers
         /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
+        Task<ItemUpdateType> RefreshSingleItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
 
         /// <summary>
         /// Saves the image.
diff --git a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
index 0ff7ee5a9d..5e2e1b4c72 100644
--- a/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
+++ b/MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Model.Providers;
 using System.Collections.Generic;
 using System.Threading;
@@ -18,37 +17,9 @@ namespace MediaBrowser.Controller.Providers
         Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken);
     }
 
-    public interface IRemoteSearchProvider : IMetadataProvider
-    {
-        /// <summary>
-        /// Gets the image response.
-        /// </summary>
-        /// <param name="url">The URL.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task{HttpResponseInfo}.</returns>
-        Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken);
-    }
-
     public interface IRemoteSearchProvider<in TLookupInfoType> : IRemoteSearchProvider
         where TLookupInfoType : ItemLookupInfo
     {
         Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken);
     }
-    
-    public class RemoteSearchQuery<T>
-        where T : ItemLookupInfo
-    {
-        public T SearchInfo { get; set; }
-
-        /// <summary>
-        /// If set will only search within the given provider
-        /// </summary>
-        public string SearchProviderName { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether [include disabled providers].
-        /// </summary>
-        /// <value><c>true</c> if [include disabled providers]; otherwise, <c>false</c>.</value>
-        public bool IncludeDisabledProviders { get; set; }
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs
new file mode 100644
index 0000000000..0077def42d
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/IRemoteSearchProvider.cs
@@ -0,0 +1,17 @@
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface IRemoteSearchProvider : IMetadataProvider
+    {
+        /// <summary>
+        /// Gets the image response.
+        /// </summary>
+        /// <param name="url">The URL.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{HttpResponseInfo}.</returns>
+        Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs b/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs
index a3adab1b90..235d0ada5a 100644
--- a/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs
+++ b/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs
@@ -7,17 +7,6 @@ using MediaBrowser.Common;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public interface ISeriesOrderProvider
-    {
-        string OrderType { get; }
-        Task<int?> FindSeriesIndex(string seriesName);
-    }
-
-    public static class SeriesOrderTypes
-    {
-        public const string Anime = "Anime";
-    }
-
     public interface ISeriesOrderManager
     {
         Task<int?> FindSeriesIndex(string orderType, string seriesName);
diff --git a/MediaBrowser.Controller/Providers/ISeriesOrderProvider.cs b/MediaBrowser.Controller/Providers/ISeriesOrderProvider.cs
new file mode 100644
index 0000000000..ee0f3c197f
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ISeriesOrderProvider.cs
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public interface ISeriesOrderProvider
+    {
+        string OrderType { get; }
+        Task<int?> FindSeriesIndex(string seriesName);
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ImageRefreshMode.cs b/MediaBrowser.Controller/Providers/ImageRefreshMode.cs
new file mode 100644
index 0000000000..df10c91f6a
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ImageRefreshMode.cs
@@ -0,0 +1,25 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public enum ImageRefreshMode
+    {
+        /// <summary>
+        /// The none
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The default
+        /// </summary>
+        Default = 1,
+
+        /// <summary>
+        /// Existing images will be validated
+        /// </summary>
+        ValidationOnly = 2,
+
+        /// <summary>
+        /// All providers will be executed to search for new metadata
+        /// </summary>
+        FullRefresh = 3
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs
new file mode 100644
index 0000000000..a66cc6f222
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class ImageRefreshOptions
+    {
+        public ImageRefreshMode ImageRefreshMode { get; set; }
+        public IDirectoryService DirectoryService { get; private set; }
+
+        public bool ReplaceAllImages { get; set; }
+
+        public List<ImageType> ReplaceImages { get; set; }
+
+        public ImageRefreshOptions(IDirectoryService directoryService)
+        {
+            ImageRefreshMode = ImageRefreshMode.Default;
+            DirectoryService = directoryService;
+
+            ReplaceImages = new List<ImageType>();
+        }
+
+        public bool IsReplacingImage(ImageType type)
+        {
+            return ImageRefreshMode == ImageRefreshMode.FullRefresh &&
+                   (ReplaceAllImages || ReplaceImages.Contains(type));
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ItemIdentities.cs b/MediaBrowser.Controller/Providers/ItemIdentities.cs
index 8d24f6c1fb..939fd3b8ff 100644
--- a/MediaBrowser.Controller/Providers/ItemIdentities.cs
+++ b/MediaBrowser.Controller/Providers/ItemIdentities.cs
@@ -1,24 +1,7 @@
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Controller.Providers
 {
-    public interface IItemIdentity
-    {
-        string Type { get; }
-    }
-
-    public interface IHasIdentities<out TIdentity>
-        where TIdentity : IItemIdentity
-    {
-        IEnumerable<TIdentity> Identities { get; }
-
-        Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken);
-    }
-
-    public interface IItemIdentityProvider : IHasOrder { }
-
     public interface IItemIdentityProvider<in TLookupInfo, TIdentity> : IItemIdentityProvider
         where TLookupInfo : ItemLookupInfo
         where TIdentity : IItemIdentity
@@ -26,8 +9,6 @@ namespace MediaBrowser.Controller.Providers
         Task<TIdentity> FindIdentity(TLookupInfo info);
     }
 
-    public interface IItemIdentityConverter : IHasOrder { }
-
     public interface IItemIdentityConverter<TIdentity> : IItemIdentityConverter
         where TIdentity : IItemIdentity
     {
diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs
new file mode 100644
index 0000000000..113a7bb8ec
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/ItemInfo.cs
@@ -0,0 +1,9 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class ItemInfo
+    {
+        public string Path { get; set; }
+
+        public bool IsInMixedFolder { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
index 43b9210923..91dc33214c 100644
--- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
+++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs
@@ -1,8 +1,4 @@
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.Channels;
-using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Entities;
 using System;
 using System.Collections.Generic;
 
@@ -43,204 +39,4 @@ namespace MediaBrowser.Controller.Providers
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
         }
     }
-
-    public interface IHasLookupInfo<out TLookupInfoType>
-        where TLookupInfoType : ItemLookupInfo, new()
-    {
-        TLookupInfoType GetLookupInfo();
-    }
-
-    public class ArtistInfo : ItemLookupInfo
-    {
-        public List<SongInfo> SongInfos { get; set; }
-
-        public ArtistInfo()
-        {
-            SongInfos = new List<SongInfo>();
-        }
-    }
-
-    public class AlbumInfo : ItemLookupInfo
-    {
-        /// <summary>
-        /// Gets or sets the album artist.
-        /// </summary>
-        /// <value>The album artist.</value>
-        public List<string> AlbumArtists { get; set; }
-
-        /// <summary>
-        /// Gets or sets the artist provider ids.
-        /// </summary>
-        /// <value>The artist provider ids.</value>
-        public Dictionary<string, string> ArtistProviderIds { get; set; }
-        public List<SongInfo> SongInfos { get; set; }
-
-        public AlbumInfo()
-        {
-            ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-            SongInfos = new List<SongInfo>();
-            AlbumArtists = new List<string>();
-        }
-    }
-
-    public class GameInfo : ItemLookupInfo
-    {
-        /// <summary>
-        /// Gets or sets the game system.
-        /// </summary>
-        /// <value>The game system.</value>
-        public string GameSystem { get; set; }
-    }
-
-    public class GameSystemInfo : ItemLookupInfo
-    {
-        /// <summary>
-        /// Gets or sets the path.
-        /// </summary>
-        /// <value>The path.</value>
-        public string Path { get; set; }
-    }
-
-    public class EpisodeInfo : ItemLookupInfo, IHasIdentities<EpisodeIdentity>
-    {
-        private List<EpisodeIdentity> _identities = new List<EpisodeIdentity>();
-
-        public Dictionary<string, string> SeriesProviderIds { get; set; }
-
-        public int? IndexNumberEnd { get; set; }
-        public int? AnimeSeriesIndex { get; set; }
-
-        public EpisodeInfo()
-        {
-            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        }
-
-        public IEnumerable<EpisodeIdentity> Identities
-        {
-            get { return _identities; }
-        }
-
-        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
-        {
-            var identifier = new ItemIdentifier<EpisodeInfo, EpisodeIdentity>();
-            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
-        }
-    }
-
-    public class EpisodeIdentity : IItemIdentity
-    {
-        public string Type { get; set; }
-
-        public string SeriesId { get; set; }
-        public int? SeasonIndex { get; set; }
-        public int IndexNumber { get; set; }
-        public int? IndexNumberEnd { get; set; }
-    }
-
-    public class SongInfo : ItemLookupInfo
-    {
-        public List<string> AlbumArtists { get; set; }
-        public string Album { get; set; }
-        public List<string> Artists { get; set; }
-
-        public SongInfo()
-        {
-            Artists = new List<string>();
-            AlbumArtists = new List<string>();
-        }
-    }
-
-    public class SeriesInfo : ItemLookupInfo, IHasIdentities<SeriesIdentity>
-    {
-        private List<SeriesIdentity> _identities = new List<SeriesIdentity>();
-
-        public int? AnimeSeriesIndex { get; set; }
-
-        public IEnumerable<SeriesIdentity> Identities
-        {
-            get { return _identities; }
-        }
-
-        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
-        {
-            var identifier = new ItemIdentifier<SeriesInfo, SeriesIdentity>();
-            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
-        }
-    }
-
-    public class SeriesIdentity : IItemIdentity
-    {
-        public string Type { get; set; }
-
-        public string Id { get; set; }
-    }
-
-    public class PersonLookupInfo : ItemLookupInfo
-    {
-        
-    }
-
-    public class MovieInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class BoxSetInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class MusicVideoInfo : ItemLookupInfo
-    {
-
-    }
-
-    public class TrailerInfo : ItemLookupInfo
-    {
-        public bool IsLocalTrailer { get; set; }
-    }
-
-    public class BookInfo : ItemLookupInfo
-    {
-        public string SeriesName { get; set; }
-    }
-
-    public class SeasonInfo : ItemLookupInfo, IHasIdentities<SeasonIdentity>
-    {
-        private List<SeasonIdentity> _identities = new List<SeasonIdentity>();
-
-        public Dictionary<string, string> SeriesProviderIds { get; set; }
-        public int? AnimeSeriesIndex { get; set; }
-
-        public SeasonInfo()
-        {
-            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        }
-
-        public IEnumerable<SeasonIdentity> Identities
-        {
-            get { return _identities; }
-        }
-
-        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
-        {
-            var identifier = new ItemIdentifier<SeasonInfo, SeasonIdentity>();
-            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
-        }
-    }
-
-    public class SeasonIdentity : IItemIdentity
-    {
-        public string Type { get; set; }
-
-        public string SeriesId { get; set; }
-
-        public int SeasonIndex { get; set; }
-    }
-
-    public class ChannelItemLookupInfo : ItemLookupInfo
-    {
-        public ChannelMediaContentType ContentType { get; set; }
-        public ExtraType ExtraType { get; set; }
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/LiveTvProgramLookupInfo.cs b/MediaBrowser.Controller/Providers/LiveTvProgramLookupInfo.cs
new file mode 100644
index 0000000000..4e2c11c22d
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/LiveTvProgramLookupInfo.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class LiveTvProgramLookupInfo : ItemLookupInfo
+    {
+        public Boolean IsMovie { get; set; }
+    }
+}
diff --git a/MediaBrowser.Controller/Providers/LocalImageInfo.cs b/MediaBrowser.Controller/Providers/LocalImageInfo.cs
new file mode 100644
index 0000000000..59d74def26
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/LocalImageInfo.cs
@@ -0,0 +1,11 @@
+using System.IO;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class LocalImageInfo
+    {
+        public FileSystemInfo FileInfo { get; set; }
+        public ImageType Type { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/LocalMetadataResult.cs b/MediaBrowser.Controller/Providers/LocalMetadataResult.cs
new file mode 100644
index 0000000000..8be3ee7aac
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/LocalMetadataResult.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class LocalMetadataResult<T>
+        where T : IHasMetadata
+    {
+        public bool HasMetadata { get; set; }
+        public T Item { get; set; }
+        
+        public List<LocalImageInfo> Images { get; set; }
+        public List<ChapterInfo> Chapters { get; set; }
+        public List<UserItemData> UserDataLIst { get; set; }
+
+        public LocalMetadataResult()
+        {
+            Images = new List<LocalImageInfo>();
+            Chapters = new List<ChapterInfo>();
+            UserDataLIst = new List<UserItemData>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs b/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs
new file mode 100644
index 0000000000..56492006a5
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/MetadataRefreshMode.cs
@@ -0,0 +1,25 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public enum MetadataRefreshMode
+    {
+        /// <summary>
+        /// The none
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// The validation only
+        /// </summary>
+        ValidationOnly = 1,
+
+        /// <summary>
+        /// Providers will be executed based on default rules
+        /// </summary>
+        Default = 2,
+
+        /// <summary>
+        /// All providers will be executed to search for new metadata
+        /// </summary>
+        FullRefresh = 3
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
index 2cd119cf51..dbb7fbfcdb 100644
--- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
+++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
@@ -1,6 +1,4 @@
-using MediaBrowser.Model.Entities;
-using System.Collections.Generic;
-using System.Linq;
+using System.Linq;
 
 namespace MediaBrowser.Controller.Providers
 {
@@ -12,7 +10,7 @@ namespace MediaBrowser.Controller.Providers
         public bool ReplaceAllMetadata { get; set; }
 
         public bool IsPostRecursiveRefresh { get; set; }
-        
+
         public MetadataRefreshMode MetadataRefreshMode { get; set; }
 
         public bool ForceSave { get; set; }
@@ -28,7 +26,7 @@ namespace MediaBrowser.Controller.Providers
             MetadataRefreshMode = MetadataRefreshMode.Default;
         }
 
-        public MetadataRefreshOptions( MetadataRefreshOptions copy)
+        public MetadataRefreshOptions(MetadataRefreshOptions copy)
             : base(copy.DirectoryService)
         {
             MetadataRefreshMode = copy.MetadataRefreshMode;
@@ -40,74 +38,4 @@ namespace MediaBrowser.Controller.Providers
             ReplaceImages = copy.ReplaceImages.ToList();
         }
     }
-
-    public class ImageRefreshOptions
-    {
-        public ImageRefreshMode ImageRefreshMode { get; set; }
-        public IDirectoryService DirectoryService { get; private set; }
-
-        public bool ReplaceAllImages { get; set; }
-
-        public List<ImageType> ReplaceImages { get; set; }
-
-        public ImageRefreshOptions(IDirectoryService directoryService)
-        {
-            ImageRefreshMode = ImageRefreshMode.Default;
-            DirectoryService = directoryService;
-
-            ReplaceImages = new List<ImageType>();
-        }
-
-        public bool IsReplacingImage(ImageType type)
-        {
-            return ImageRefreshMode == ImageRefreshMode.FullRefresh &&
-                (ReplaceAllImages || ReplaceImages.Contains(type));
-        }
-    }
-
-    public enum MetadataRefreshMode
-    {
-        /// <summary>
-        /// The none
-        /// </summary>
-        None = 0,
-
-        /// <summary>
-        /// The validation only
-        /// </summary>
-        ValidationOnly = 1,
-
-        /// <summary>
-        /// Providers will be executed based on default rules
-        /// </summary>
-        Default = 2,
-
-        /// <summary>
-        /// All providers will be executed to search for new metadata
-        /// </summary>
-        FullRefresh = 3
-    }
-
-    public enum ImageRefreshMode
-    {
-        /// <summary>
-        /// The none
-        /// </summary>
-        None = 0,
-
-        /// <summary>
-        /// The default
-        /// </summary>
-        Default = 1,
-
-        /// <summary>
-        /// Existing images will be validated
-        /// </summary>
-        ValidationOnly = 2,
-
-        /// <summary>
-        /// All providers will be executed to search for new metadata
-        /// </summary>
-        FullRefresh = 3
-    }
 }
diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs
new file mode 100644
index 0000000000..756458cfaf
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/MetadataResult.cs
@@ -0,0 +1,8 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class MetadataResult<T>
+    {
+        public bool HasMetadata { get; set; }
+        public T Item { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/MovieInfo.cs b/MediaBrowser.Controller/Providers/MovieInfo.cs
new file mode 100644
index 0000000000..198336fc01
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/MovieInfo.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class MovieInfo : ItemLookupInfo
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/MusicVideoInfo.cs b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
new file mode 100644
index 0000000000..4f4ab5954a
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/MusicVideoInfo.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class MusicVideoInfo : ItemLookupInfo
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/PersonLookupInfo.cs b/MediaBrowser.Controller/Providers/PersonLookupInfo.cs
new file mode 100644
index 0000000000..db4dacb0b4
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/PersonLookupInfo.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class PersonLookupInfo : ItemLookupInfo
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs
new file mode 100644
index 0000000000..cd86f352fe
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs
@@ -0,0 +1,19 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class RemoteSearchQuery<T>
+        where T : ItemLookupInfo
+    {
+        public T SearchInfo { get; set; }
+
+        /// <summary>
+        /// If set will only search within the given provider
+        /// </summary>
+        public string SearchProviderName { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether [include disabled providers].
+        /// </summary>
+        /// <value><c>true</c> if [include disabled providers]; otherwise, <c>false</c>.</value>
+        public bool IncludeDisabledProviders { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeasonIdentity.cs b/MediaBrowser.Controller/Providers/SeasonIdentity.cs
new file mode 100644
index 0000000000..1e6b9b65a3
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/SeasonIdentity.cs
@@ -0,0 +1,11 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeasonIdentity : IItemIdentity
+    {
+        public string Type { get; set; }
+
+        public string SeriesId { get; set; }
+
+        public int SeasonIndex { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeasonInfo.cs b/MediaBrowser.Controller/Providers/SeasonInfo.cs
new file mode 100644
index 0000000000..17bcd3f772
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/SeasonInfo.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeasonInfo : ItemLookupInfo, IHasIdentities<SeasonIdentity>
+    {
+        private List<SeasonIdentity> _identities = new List<SeasonIdentity>();
+
+        public Dictionary<string, string> SeriesProviderIds { get; set; }
+        public int? AnimeSeriesIndex { get; set; }
+
+        public SeasonInfo()
+        {
+            SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public IEnumerable<SeasonIdentity> Identities
+        {
+            get { return _identities; }
+        }
+
+        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
+        {
+            var identifier = new ItemIdentifier<SeasonInfo, SeasonIdentity>();
+            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeriesIdentity.cs b/MediaBrowser.Controller/Providers/SeriesIdentity.cs
new file mode 100644
index 0000000000..326d340275
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/SeriesIdentity.cs
@@ -0,0 +1,9 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeriesIdentity : IItemIdentity
+    {
+        public string Type { get; set; }
+
+        public string Id { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeriesInfo.cs b/MediaBrowser.Controller/Providers/SeriesInfo.cs
new file mode 100644
index 0000000000..fc1119cd25
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/SeriesInfo.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class SeriesInfo : ItemLookupInfo, IHasIdentities<SeriesIdentity>
+    {
+        private List<SeriesIdentity> _identities = new List<SeriesIdentity>();
+
+        public int? AnimeSeriesIndex { get; set; }
+
+        public IEnumerable<SeriesIdentity> Identities
+        {
+            get { return _identities; }
+        }
+
+        public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
+        {
+            var identifier = new ItemIdentifier<SeriesInfo, SeriesIdentity>();
+            _identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SeriesOrderTypes.cs b/MediaBrowser.Controller/Providers/SeriesOrderTypes.cs
new file mode 100644
index 0000000000..5e04fb4dbc
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/SeriesOrderTypes.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public static class SeriesOrderTypes
+    {
+        public const string Anime = "Anime";
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/SongInfo.cs b/MediaBrowser.Controller/Providers/SongInfo.cs
new file mode 100644
index 0000000000..b83912a002
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/SongInfo.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Providers
+{
+    public class SongInfo : ItemLookupInfo
+    {
+        public List<string> AlbumArtists { get; set; }
+        public string Album { get; set; }
+        public List<string> Artists { get; set; }
+
+        public SongInfo()
+        {
+            Artists = new List<string>();
+            AlbumArtists = new List<string>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Providers/TrailerInfo.cs b/MediaBrowser.Controller/Providers/TrailerInfo.cs
new file mode 100644
index 0000000000..fe26ec43ec
--- /dev/null
+++ b/MediaBrowser.Controller/Providers/TrailerInfo.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Controller.Providers
+{
+    public class TrailerInfo : ItemLookupInfo
+    {
+        public bool IsLocalTrailer { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Security/AuthenticationInfo.cs b/MediaBrowser.Controller/Security/AuthenticationInfo.cs
index dd5eec1f92..c2d4a39d1b 100644
--- a/MediaBrowser.Controller/Security/AuthenticationInfo.cs
+++ b/MediaBrowser.Controller/Security/AuthenticationInfo.cs
@@ -28,6 +28,12 @@ namespace MediaBrowser.Controller.Security
         /// <value>The name of the application.</value>
         public string AppName { get; set; }
 
+        /// <summary>
+        /// Gets or sets the application version.
+        /// </summary>
+        /// <value>The application version.</value>
+        public string AppVersion { get; set; }
+        
         /// <summary>
         /// Gets or sets the name of the device.
         /// </summary>
diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs
index 4082f56008..80025171dc 100644
--- a/MediaBrowser.Controller/Session/ISessionManager.cs
+++ b/MediaBrowser.Controller/Session/ISessionManager.cs
@@ -1,5 +1,6 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Security;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Session;
@@ -73,7 +74,7 @@ namespace MediaBrowser.Controller.Session
         /// <summary>
         /// Logs the user activity.
         /// </summary>
-        /// <param name="clientType">Type of the client.</param>
+        /// <param name="appName">Type of the client.</param>
         /// <param name="appVersion">The app version.</param>
         /// <param name="deviceId">The device id.</param>
         /// <param name="deviceName">Name of the device.</param>
@@ -81,7 +82,7 @@ namespace MediaBrowser.Controller.Session
         /// <param name="user">The user.</param>
         /// <returns>Task.</returns>
         /// <exception cref="System.ArgumentNullException">user</exception>
-        Task<SessionInfo> LogSessionActivity(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user);
+        Task<SessionInfo> LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user);
 
         /// <summary>
         /// Used to report that playback has started for an item
@@ -278,6 +279,25 @@ namespace MediaBrowser.Controller.Session
         /// <returns>SessionInfo.</returns>
         SessionInfo GetSession(string deviceId, string client, string version);
 
+        /// <summary>
+        /// Gets the session by authentication token.
+        /// </summary>
+        /// <param name="token">The token.</param>
+        /// <param name="deviceId">The device identifier.</param>
+        /// <param name="remoteEndpoint">The remote endpoint.</param>
+        /// <returns>SessionInfo.</returns>
+        Task<SessionInfo> GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint);
+
+        /// <summary>
+        /// Gets the session by authentication token.
+        /// </summary>
+        /// <param name="info">The information.</param>
+        /// <param name="deviceId">The device identifier.</param>
+        /// <param name="remoteEndpoint">The remote endpoint.</param>
+        /// <param name="appVersion">The application version.</param>
+        /// <returns>Task&lt;SessionInfo&gt;.</returns>
+        Task<SessionInfo> GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion);
+
         /// <summary>
         /// Logouts the specified access token.
         /// </summary>
diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs
index 078d4d70ff..64b20c13ef 100644
--- a/MediaBrowser.Controller/Session/SessionInfo.cs
+++ b/MediaBrowser.Controller/Session/SessionInfo.cs
@@ -14,17 +14,8 @@ namespace MediaBrowser.Controller.Session
         public SessionInfo()
         {
             QueueableMediaTypes = new List<string>();
-            PlayableMediaTypes = new List<string>
-            {
-                MediaType.Audio,
-                MediaType.Book,
-                MediaType.Game,
-                MediaType.Photo,
-                MediaType.Video
-            };
 
             AdditionalUsers = new List<SessionUserInfo>();
-            SupportedCommands = new List<string>();
             PlayState = new PlayerStateInfo();
         }
 
@@ -32,6 +23,8 @@ namespace MediaBrowser.Controller.Session
         
         public List<SessionUserInfo> AdditionalUsers { get; set; }
 
+        public ClientCapabilities Capabilities { get; set; }
+
         /// <summary>
         /// Gets or sets the remote end point.
         /// </summary>
@@ -48,7 +41,17 @@ namespace MediaBrowser.Controller.Session
         /// Gets or sets the playable media types.
         /// </summary>
         /// <value>The playable media types.</value>
-        public List<string> PlayableMediaTypes { get; set; }
+        public List<string> PlayableMediaTypes
+        {
+            get
+            {
+                if (Capabilities == null)
+                {
+                    return new List<string>();
+                }
+                return Capabilities.PlayableMediaTypes;
+            }
+        }
 
         /// <summary>
         /// Gets or sets the id.
@@ -126,7 +129,17 @@ namespace MediaBrowser.Controller.Session
         /// Gets or sets the supported commands.
         /// </summary>
         /// <value>The supported commands.</value>
-        public List<string> SupportedCommands { get; set; }
+        public List<string> SupportedCommands
+        {
+            get
+            {
+                if (Capabilities == null)
+                {
+                    return new List<string>();
+                }
+                return Capabilities.SupportedCommands;
+            }
+        }
 
         public TranscodingInfo TranscodingInfo { get; set; }
 
@@ -151,6 +164,11 @@ namespace MediaBrowser.Controller.Session
         {
             get
             {
+                if (Capabilities == null || !Capabilities.SupportsMediaControl)
+                {
+                    return false;
+                }
+
                 if (SessionController != null)
                 {
                     return SessionController.SupportsMediaControl;
diff --git a/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs b/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs
deleted file mode 100644
index f9327a71c3..0000000000
--- a/MediaBrowser.Controller/Sync/ICloudSyncProvider.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using MediaBrowser.Model.Sync;
-using System.Collections.Generic;
-
-namespace MediaBrowser.Controller.Sync
-{
-    public interface ICloudSyncProvider
-    {
-        /// <summary>
-        /// Gets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        string Name { get; }
-
-        /// <summary>
-        /// Gets the synchronize targets.
-        /// </summary>
-        /// <param name="userId">The user identifier.</param>
-        /// <returns>IEnumerable&lt;SyncTarget&gt;.</returns>
-        IEnumerable<SyncTarget> GetSyncTargets(string userId);
-    }
-}
diff --git a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
index 8ef54fd432..abf884e9d5 100644
--- a/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/IServerSyncProvider.cs
@@ -1,5 +1,7 @@
 using MediaBrowser.Model.Sync;
+using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -8,35 +10,58 @@ namespace MediaBrowser.Controller.Sync
     public interface IServerSyncProvider : ISyncProvider
     {
         /// <summary>
-        /// Gets the server item ids.
+        /// Transfers the file.
         /// </summary>
-        /// <param name="serverId">The server identifier.</param>
+        /// <param name="stream">The stream.</param>
+        /// <param name="remotePath">The remote path.</param>
         /// <param name="target">The target.</param>
+        /// <param name="progress">The progress.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task&lt;List&lt;System.String&gt;&gt;.</returns>
-        Task<List<string>> GetServerItemIds(string serverId, SyncTarget target, CancellationToken cancellationToken);
+        /// <returns>Task.</returns>
+        Task<SendFileResult> SendFile(Stream stream, string remotePath, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
 
         /// <summary>
-        /// Removes the item.
+        /// Deletes the file.
         /// </summary>
-        /// <param name="serverId">The server identifier.</param>
-        /// <param name="itemId">The item identifier.</param>
+        /// <param name="path">The path.</param>
         /// <param name="target">The target.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task DeleteItem(string serverId, string itemId, SyncTarget target, CancellationToken cancellationToken);
+        Task DeleteFile(string path, SyncTarget target, CancellationToken cancellationToken);
 
         /// <summary>
-        /// Transfers the file.
+        /// Gets the file.
         /// </summary>
-        /// <param name="serverId">The server identifier.</param>
-        /// <param name="itemId">The item identifier.</param>
-        /// <param name="pathParts">The path parts.</param>
-        /// <param name="name">The name.</param>
-        /// <param name="fileType">Type of the file.</param>
+        /// <param name="path">The path.</param>
         /// <param name="target">The target.</param>
+        /// <param name="progress">The progress.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task.</returns>
-        Task TransferItemFile(string serverId, string itemId, string[] pathParts, string name, ItemFileType fileType, SyncTarget target, CancellationToken cancellationToken);
+        /// <returns>Task&lt;Stream&gt;.</returns>
+        Task<Stream> GetFile(string path, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// Gets the full path.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="target">The target.</param>
+        /// <returns>System.String.</returns>
+        string GetFullPath(IEnumerable<string> path, SyncTarget target);
+
+        /// <summary>
+        /// Gets the parent directory path.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="target">The target.</param>
+        /// <returns>System.String.</returns>
+        string GetParentDirectoryPath(string path, SyncTarget target);
+
+        /// <summary>
+        /// Gets the file system entries.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="target">The target.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task&lt;List&lt;DeviceFileInfo&gt;&gt;.</returns>
+        Task<List<DeviceFileInfo>> GetFileSystemEntries(string path, SyncTarget target, CancellationToken cancellationToken);
     }
 }
diff --git a/MediaBrowser.Controller/Sync/ISyncDataProvider.cs b/MediaBrowser.Controller/Sync/ISyncDataProvider.cs
new file mode 100644
index 0000000000..f84748b971
--- /dev/null
+++ b/MediaBrowser.Controller/Sync/ISyncDataProvider.cs
@@ -0,0 +1,50 @@
+using MediaBrowser.Model.Sync;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Sync
+{
+    public interface ISyncDataProvider
+    {
+        /// <summary>
+        /// Gets the server item ids.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="serverId">The server identifier.</param>
+        /// <returns>Task&lt;List&lt;System.String&gt;&gt;.</returns>
+        Task<List<string>> GetServerItemIds(SyncTarget target, string serverId);
+
+        /// <summary>
+        /// Adds the or update.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="item">The item.</param>
+        /// <returns>Task.</returns>
+        Task AddOrUpdate(SyncTarget target, LocalItem item);
+
+        /// <summary>
+        /// Deletes the specified identifier.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Task.</returns>
+        Task Delete(SyncTarget target, string id);
+
+        /// <summary>
+        /// Gets the specified identifier.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Task&lt;LocalItem&gt;.</returns>
+        Task<LocalItem> Get(SyncTarget target, string id);
+
+        /// <summary>
+        /// Gets the cached item.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="serverId">The server identifier.</param>
+        /// <param name="itemId">The item identifier.</param>
+        /// <returns>Task&lt;LocalItem&gt;.</returns>
+        Task<List<LocalItem>> GetCachedItems(SyncTarget target, string serverId, string itemId);
+    }
+}
diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs
index 4b800cac96..c51c8c1ba9 100644
--- a/MediaBrowser.Controller/Sync/ISyncManager.cs
+++ b/MediaBrowser.Controller/Sync/ISyncManager.cs
@@ -90,13 +90,6 @@ namespace MediaBrowser.Controller.Sync
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         bool SupportsSync(BaseItem item);
 
-        /// <summary>
-        /// Gets the device profile.
-        /// </summary>
-        /// <param name="targetId">The target identifier.</param>
-        /// <returns>DeviceProfile.</returns>
-        DeviceProfile GetDeviceProfile(string targetId);
-
         /// <summary>
         /// Reports the synchronize job item transferred.
         /// </summary>
@@ -153,21 +146,6 @@ namespace MediaBrowser.Controller.Sync
         /// <returns>QueryResult&lt;System.String&gt;.</returns>
         QueryResult<string> GetLibraryItemIds(SyncJobItemQuery query);
 
-        /// <summary>
-        /// Gets the audio options.
-        /// </summary>
-        /// <param name="jobItem">The job item.</param>
-        /// <returns>AudioOptions.</returns>
-        AudioOptions GetAudioOptions(SyncJobItem jobItem);
-
-        /// <summary>
-        /// Gets the video options.
-        /// </summary>
-        /// <param name="jobItem">The job item.</param>
-        /// <param name="job">The job.</param>
-        /// <returns>VideoOptions.</returns>
-        VideoOptions GetVideoOptions(SyncJobItem jobItem, SyncJob job);
-
         /// <summary>
         /// Reports the synchronize job item transfer beginning.
         /// </summary>
@@ -181,5 +159,19 @@ namespace MediaBrowser.Controller.Sync
         /// <param name="id">The identifier.</param>
         /// <returns>Task.</returns>
         Task ReportSyncJobItemTransferFailed(string id);
+
+        /// <summary>
+        /// Gets the quality options.
+        /// </summary>
+        /// <param name="targetId">The target identifier.</param>
+        /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
+        IEnumerable<SyncQualityOption> GetQualityOptions(string targetId);
+
+        /// <summary>
+        /// Gets the profile options.
+        /// </summary>
+        /// <param name="targetId">The target identifier.</param>
+        /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
+        IEnumerable<SyncProfileOption> GetProfileOptions(string targetId);
     }
 }
diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs
index 6f24eac1ae..ef34bfe692 100644
--- a/MediaBrowser.Controller/Sync/ISyncProvider.cs
+++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Sync;
+using MediaBrowser.Model.Sync;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Controller.Sync
@@ -18,13 +17,12 @@ namespace MediaBrowser.Controller.Sync
         /// <param name="userId">The user identifier.</param>
         /// <returns>IEnumerable&lt;SyncTarget&gt;.</returns>
         IEnumerable<SyncTarget> GetSyncTargets(string userId);
-        
+
         /// <summary>
-        /// Gets the device profile.
+        /// Gets all synchronize targets.
         /// </summary>
-        /// <param name="target">The target.</param>
-        /// <returns>DeviceProfile.</returns>
-        DeviceProfile GetDeviceProfile(SyncTarget target);
+        /// <returns>IEnumerable&lt;SyncTarget&gt;.</returns>
+        IEnumerable<SyncTarget> GetAllSyncTargets();
     }
 
     public interface IHasUniqueTargetIds
diff --git a/MediaBrowser.Controller/Sync/SendFileResult.cs b/MediaBrowser.Controller/Sync/SendFileResult.cs
new file mode 100644
index 0000000000..62753444a4
--- /dev/null
+++ b/MediaBrowser.Controller/Sync/SendFileResult.cs
@@ -0,0 +1,18 @@
+using MediaBrowser.Model.MediaInfo;
+
+namespace MediaBrowser.Controller.Sync
+{
+    public class SendFileResult
+    {
+        /// <summary>
+        /// Gets or sets the path.
+        /// </summary>
+        /// <value>The path.</value>
+        public string Path { get; set; }
+        /// <summary>
+        /// Gets or sets the protocol.
+        /// </summary>
+        /// <value>The protocol.</value>
+        public MediaProtocol Protocol { get; set; }
+    }
+}
diff --git a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
index 75f1579ac4..2ab27fde50 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
@@ -25,6 +25,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
         private readonly IUserManager _userManager;
         private readonly ILocalizationManager _localization;
         private readonly IChannelManager _channelManager;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
         public ContentDirectory(IDlnaManager dlna,
             IUserDataManager userDataManager,
@@ -33,7 +34,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
             IServerConfigurationManager config,
             IUserManager userManager,
             ILogger logger,
-            IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager)
+            IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager)
             : base(logger, httpClient)
         {
             _dlna = dlna;
@@ -44,6 +45,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
             _userManager = userManager;
             _localization = localization;
             _channelManager = channelManager;
+            _mediaSourceManager = mediaSourceManager;
         }
 
         private int SystemUpdateId
@@ -83,7 +85,8 @@ namespace MediaBrowser.Dlna.ContentDirectory
                 SystemUpdateId,
                 _config,
                 _localization,
-                _channelManager)
+                _channelManager,
+                _mediaSourceManager)
                 .ProcessControlRequest(request);
         }
 
diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index 5d6ee5c73e..5ccea52bad 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -11,6 +11,7 @@ using MediaBrowser.Dlna.Didl;
 using MediaBrowser.Dlna.Server;
 using MediaBrowser.Dlna.Service;
 using MediaBrowser.Model.Channels;
+using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
@@ -31,6 +32,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
         private readonly ILibraryManager _libraryManager;
         private readonly IChannelManager _channelManager;
         private readonly IUserDataManager _userDataManager;
+        private readonly IServerConfigurationManager _config;
         private readonly User _user;
 
         private const string NS_DC = "http://purl.org/dc/elements/1.1/";
@@ -45,7 +47,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
 
         private readonly DeviceProfile _profile;
 
-        public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager)
+        public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager)
             : base(config, logger)
         {
             _libraryManager = libraryManager;
@@ -54,8 +56,9 @@ namespace MediaBrowser.Dlna.ContentDirectory
             _systemUpdateId = systemUpdateId;
             _channelManager = channelManager;
             _profile = profile;
+            _config = config;
 
-            _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization);
+            _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager);
         }
 
         protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
@@ -465,12 +468,14 @@ namespace MediaBrowser.Dlna.ContentDirectory
 
             }).ConfigureAwait(false);
 
+            var options = _config.GetDlnaConfiguration();
+
             var serverItems = queryResult
                 .Items
                 .Select(i => new ServerItem
                 {
                     Item = i,
-                    StubType = GetDisplayStubType(i, item)
+                    StubType = GetDisplayStubType(i, item, options)
                 })
                 .ToArray();
 
@@ -539,23 +544,23 @@ namespace MediaBrowser.Dlna.ContentDirectory
             return result;
         }
 
-        private StubType? GetDisplayStubType(BaseItem item, BaseItem context)
+        private StubType? GetDisplayStubType(BaseItem item, BaseItem context, DlnaOptions options)
         {
             if (context == null || context.IsFolder)
             {
                 var movie = item as Movie;
-                if (movie != null)
+                if (movie != null && options.EnableEnhancedMovies)
                 {
                     if (movie.GetTrailerIds().Count > 0 ||
                         movie.SpecialFeatureIds.Count > 0)
                     {
                         return StubType.Folder;
                     }
-                }
 
-                if (EnablePeopleDisplay(item))
-                {
-                    return StubType.Folder;
+                    if (EnablePeopleDisplay(item))
+                    {
+                        return StubType.Folder;
+                    }
                 }
             }
 
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index af7c8dbed0..469b60a9c2 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -37,14 +37,16 @@ namespace MediaBrowser.Dlna.Didl
         private readonly User _user;
         private readonly IUserDataManager _userDataManager;
         private readonly ILocalizationManager _localization;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
-        public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization)
+        public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         {
             _profile = profile;
             _imageProcessor = imageProcessor;
             _serverAddress = serverAddress;
             _userDataManager = userDataManager;
             _localization = localization;
+            _mediaSourceManager = mediaSourceManager;
             _accessToken = accessToken;
             _user = user;
         }
@@ -122,7 +124,7 @@ namespace MediaBrowser.Dlna.Didl
         {
             if (streamInfo == null)
             {
-                var sources = _user == null ? video.GetMediaSources(true).ToList() : video.GetMediaSources(true, _user).ToList();
+                var sources = _user == null ? video.GetMediaSources(true).ToList() : _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList();
 
                 streamInfo = new StreamBuilder().BuildVideoItem(new VideoOptions
                 {
@@ -342,7 +344,7 @@ namespace MediaBrowser.Dlna.Didl
 
             if (streamInfo == null)
             {
-                var sources = _user == null ? audio.GetMediaSources(true).ToList() : audio.GetMediaSources(true, _user).ToList();
+                var sources = _user == null ? audio.GetMediaSources(true).ToList() : _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList();
 
                 streamInfo = new StreamBuilder().BuildAudioItem(new AudioOptions
                {
@@ -930,7 +932,7 @@ namespace MediaBrowser.Dlna.Didl
 
             try
             {
-                var size = _imageProcessor.GetImageSize(imageInfo.Path, imageInfo.DateModified);
+                var size = _imageProcessor.GetImageSize(imageInfo);
 
                 width = Convert.ToInt32(size.Width);
                 height = Convert.ToInt32(size.Height);
diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
index f3e8c108bc..4a8baf0feb 100644
--- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
+++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
@@ -7,7 +7,6 @@ using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Dlna.Channels;
@@ -30,13 +29,13 @@ namespace MediaBrowser.Dlna.Main
         private PlayToManager _manager;
         private readonly ISessionManager _sessionManager;
         private readonly IHttpClient _httpClient;
-        private readonly IItemRepository _itemRepo;
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
         private readonly IDlnaManager _dlnaManager;
         private readonly IImageProcessor _imageProcessor;
         private readonly IUserDataManager _userDataManager;
         private readonly ILocalizationManager _localization;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
         private SsdpHandler _ssdpHandler;
         private DeviceDiscovery _deviceDiscovery;
@@ -44,20 +43,20 @@ namespace MediaBrowser.Dlna.Main
         private readonly List<string> _registeredServerIds = new List<string>();
         private bool _dlnaServerStarted;
 
-        public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor, IUserDataManager userDataManager, ILocalizationManager localization)
+        public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         {
             _config = config;
             _appHost = appHost;
             _network = network;
             _sessionManager = sessionManager;
             _httpClient = httpClient;
-            _itemRepo = itemRepo;
             _libraryManager = libraryManager;
             _userManager = userManager;
             _dlnaManager = dlnaManager;
             _imageProcessor = imageProcessor;
             _userDataManager = userDataManager;
             _localization = localization;
+            _mediaSourceManager = mediaSourceManager;
             _logger = logManager.GetLogger("Dlna");
         }
 
@@ -217,7 +216,6 @@ namespace MediaBrowser.Dlna.Main
                 {
                     _manager = new PlayToManager(_logger,
                         _sessionManager,
-                        _itemRepo,
                         _libraryManager,
                         _userManager,
                         _dlnaManager,
@@ -227,7 +225,8 @@ namespace MediaBrowser.Dlna.Main
                         _httpClient,
                         _config,
                         _userDataManager,
-                        _localization);
+                        _localization,
+                        _mediaSourceManager);
 
                     _manager.Start();
                 }
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index 5746231618..f53318069c 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Dlna.Didl;
 using MediaBrowser.Dlna.Ssdp;
@@ -27,7 +26,6 @@ namespace MediaBrowser.Dlna.PlayTo
         private Device _device;
         private readonly SessionInfo _session;
         private readonly ISessionManager _sessionManager;
-        private readonly IItemRepository _itemRepository;
         private readonly ILibraryManager _libraryManager;
         private readonly ILogger _logger;
         private readonly IDlnaManager _dlnaManager;
@@ -35,6 +33,7 @@ namespace MediaBrowser.Dlna.PlayTo
         private readonly IImageProcessor _imageProcessor;
         private readonly IUserDataManager _userDataManager;
         private readonly ILocalizationManager _localization;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
         private readonly DeviceDiscovery _deviceDiscovery;
         private readonly string _serverAddress;
@@ -55,10 +54,9 @@ namespace MediaBrowser.Dlna.PlayTo
 
         private Timer _updateTimer;
 
-        public PlayToController(SessionInfo session, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, DeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization)
+        public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, DeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         {
             _session = session;
-            _itemRepository = itemRepository;
             _sessionManager = sessionManager;
             _libraryManager = libraryManager;
             _dlnaManager = dlnaManager;
@@ -68,6 +66,7 @@ namespace MediaBrowser.Dlna.PlayTo
             _deviceDiscovery = deviceDiscovery;
             _userDataManager = userDataManager;
             _localization = localization;
+            _mediaSourceManager = mediaSourceManager;
             _accessToken = accessToken;
             _logger = logger;
         }
@@ -140,7 +139,7 @@ namespace MediaBrowser.Dlna.PlayTo
         {
             try
             {
-                var streamInfo = StreamParams.ParseFromUrl(e.OldMediaInfo.Url, _libraryManager);
+                var streamInfo = StreamParams.ParseFromUrl(e.OldMediaInfo.Url, _libraryManager, _mediaSourceManager);
                 if (streamInfo.Item != null)
                 {
                     var progress = GetProgressInfo(e.OldMediaInfo, streamInfo);
@@ -150,7 +149,7 @@ namespace MediaBrowser.Dlna.PlayTo
                     ReportPlaybackStopped(e.OldMediaInfo, streamInfo, positionTicks);
                 }
 
-                streamInfo = StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager);
+                streamInfo = StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager, _mediaSourceManager);
                 if (streamInfo.Item == null) return;
                 
                 var newItemProgress = GetProgressInfo(e.NewMediaInfo, streamInfo);
@@ -167,7 +166,7 @@ namespace MediaBrowser.Dlna.PlayTo
         {
             try
             {
-                var streamInfo = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager);
+                var streamInfo = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
 
                 if (streamInfo.Item == null) return;
 
@@ -229,7 +228,7 @@ namespace MediaBrowser.Dlna.PlayTo
         {
             try
             {
-                var info = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager);
+                var info = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
 
                 if (info.Item != null)
                 {
@@ -248,7 +247,7 @@ namespace MediaBrowser.Dlna.PlayTo
         {
             try
             {
-                var info = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager);
+                var info = StreamParams.ParseFromUrl(e.MediaInfo.Url, _libraryManager, _mediaSourceManager);
 
                 if (info.Item != null)
                 {
@@ -376,7 +375,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             if (media != null)
             {
-                var info = StreamParams.ParseFromUrl(media.Url, _libraryManager);
+                var info = StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager);
 
                 if (info.Item != null && !info.IsDirectStream)
                 {
@@ -472,7 +471,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             var hasMediaSources = item as IHasMediaSources;
             var mediaSources = hasMediaSources != null
-                ? (user == null ? hasMediaSources.GetMediaSources(true) : hasMediaSources.GetMediaSources(true, user)).ToList()
+                ? (user == null ? hasMediaSources.GetMediaSources(true) : _mediaSourceManager.GetStaticMediaSources(hasMediaSources, true, user)).ToList()
                 : new List<MediaSourceInfo>();
 
             var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
@@ -480,7 +479,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             playlistItem.StreamUrl = playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken);
 
-            var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization)
+            var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager)
                 .GetItemDidl(item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
 
             playlistItem.Didl = itemXml;
@@ -737,7 +736,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             if (media != null)
             {
-                var info = StreamParams.ParseFromUrl(media.Url, _libraryManager);
+                var info = StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager);
 
                 if (info.Item != null)
                 {
@@ -763,7 +762,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             if (media != null)
             {
-                var info = StreamParams.ParseFromUrl(media.Url, _libraryManager);
+                var info = StreamParams.ParseFromUrl(media.Url, _libraryManager, _mediaSourceManager);
 
                 if (info.Item != null)
                 {
@@ -824,7 +823,7 @@ namespace MediaBrowser.Dlna.PlayTo
                 return null;
             }
 
-            public static StreamParams ParseFromUrl(string url, ILibraryManager libraryManager)
+            public static StreamParams ParseFromUrl(string url, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager)
             {
                 var request = new StreamParams
                 {
@@ -892,7 +891,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
                 request.MediaSource = hasMediaSources == null ?
                     null :
-                    hasMediaSources.GetMediaSources(false).FirstOrDefault(i => string.Equals(i.Id, request.MediaSourceId, StringComparison.OrdinalIgnoreCase));
+                    mediaSourceManager.GetStaticMediaSource(hasMediaSources, request.MediaSourceId, false);
 
 
 
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
index 9a9a976d35..ba6d656ddc 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs
@@ -5,7 +5,6 @@ using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Localization;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Dlna.Ssdp;
 using MediaBrowser.Model.Logging;
@@ -22,7 +21,6 @@ namespace MediaBrowser.Dlna.PlayTo
         private readonly ILogger _logger;
         private readonly ISessionManager _sessionManager;
 
-        private readonly IItemRepository _itemRepository;
         private readonly ILibraryManager _libraryManager;
         private readonly IUserManager _userManager;
         private readonly IDlnaManager _dlnaManager;
@@ -34,12 +32,12 @@ namespace MediaBrowser.Dlna.PlayTo
         private readonly ILocalizationManager _localization;
 
         private readonly DeviceDiscovery _deviceDiscovery;
-        
-        public PlayToManager(ILogger logger, ISessionManager sessionManager, IItemRepository itemRepository, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization)
+        private readonly IMediaSourceManager _mediaSourceManager;
+
+        public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         {
             _logger = logger;
             _sessionManager = sessionManager;
-            _itemRepository = itemRepository;
             _libraryManager = libraryManager;
             _userManager = userManager;
             _dlnaManager = dlnaManager;
@@ -50,6 +48,7 @@ namespace MediaBrowser.Dlna.PlayTo
             _config = config;
             _userDataManager = userDataManager;
             _localization = localization;
+            _mediaSourceManager = mediaSourceManager;
         }
 
         public void Start()
@@ -102,7 +101,6 @@ namespace MediaBrowser.Dlna.PlayTo
 
                         sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
                             _sessionManager,
-                            _itemRepository,
                             _libraryManager,
                             _logger,
                             _dlnaManager,
@@ -112,7 +110,8 @@ namespace MediaBrowser.Dlna.PlayTo
                             accessToken,
                             _deviceDiscovery,
                             _userDataManager,
-                            _localization);
+                            _localization,
+                            _mediaSourceManager);
 
                         controller.Init(device);
 
diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
index 194b3cd23b..c59d574bf4 100644
--- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
+++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs
@@ -57,6 +57,7 @@ namespace MediaBrowser.LocalMetadata.Savers
                     
                     "Language",
                     "LocalTitle",
+                    "OriginalTitle",
                     "LockData",
                     "LockedFields",
                     "Format3D",
@@ -273,6 +274,15 @@ namespace MediaBrowser.LocalMetadata.Savers
             {
                 builder.Append("<Overview><![CDATA[" + item.Overview + "]]></Overview>");
             }
+
+            var hasOriginalTitle = item as IHasOriginalTitle;
+            if (hasOriginalTitle != null)
+            {
+                if (!string.IsNullOrEmpty(hasOriginalTitle.OriginalTitle))
+                {
+                    builder.Append("<OriginalTitle>" + SecurityElement.Escape(hasOriginalTitle.OriginalTitle) + "</OriginalTitle>");
+                }
+            }
             
             var hasShortOverview = item as IHasShortOverview;
             if (hasShortOverview != null)
@@ -751,11 +761,6 @@ namespace MediaBrowser.LocalMetadata.Savers
                     builder.Append("<Type>" + SecurityElement.Escape(link.ItemType) + "</Type>");
                 }
 
-                if (link.ItemYear.HasValue)
-                {
-                    builder.Append("<Year>" + SecurityElement.Escape(link.ItemYear.Value.ToString(UsCulture)) + "</Year>");
-                }
-
                 if (!string.IsNullOrWhiteSpace(link.Path))
                 {
                     builder.Append("<Path>" + SecurityElement.Escape((link.Path)) + "</Path>");
diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
index 52221d349e..a6a87a3fcb 100644
--- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 {
     public class AudioEncoder : BaseEncoder
     {
-        public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder) : base(mediaEncoder, logger, configurationManager, fileSystem, liveTvManager, isoManager, libraryManager, channelManager, sessionManager, subtitleEncoder)
+        public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, liveTvManager, isoManager, libraryManager, channelManager, sessionManager, subtitleEncoder, mediaSourceManager)
         {
         }
 
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
index ffae8612ed..6ddc3487de 100644
--- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
@@ -36,6 +36,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
         protected readonly IChannelManager ChannelManager;
         protected readonly ISessionManager SessionManager;
         protected readonly ISubtitleEncoder SubtitleEncoder;
+        protected readonly IMediaSourceManager MediaSourceManager;
 
         protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
@@ -47,7 +48,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             IIsoManager isoManager,
             ILibraryManager libraryManager,
             IChannelManager channelManager,
-            ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder)
+            ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager)
         {
             MediaEncoder = mediaEncoder;
             Logger = logger;
@@ -59,13 +60,14 @@ namespace MediaBrowser.MediaEncoding.Encoder
             ChannelManager = channelManager;
             SessionManager = sessionManager;
             SubtitleEncoder = subtitleEncoder;
+            MediaSourceManager = mediaSourceManager;
         }
 
         public async Task<EncodingJob> Start(EncodingJobOptions options,
             IProgress<double> progress,
             CancellationToken cancellationToken)
         {
-            var encodingJob = await new EncodingJobFactory(Logger, LiveTvManager, LibraryManager, ChannelManager)
+            var encodingJob = await new EncodingJobFactory(Logger, LiveTvManager, LibraryManager, ChannelManager, MediaSourceManager)
                 .CreateJob(options, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false);
 
             encodingJob.OutputFilePath = GetOutputFilePath(encodingJob);
@@ -452,24 +454,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
         private string GetInputPathArgument(EncodingJob job)
         {
-            //if (job.InputProtocol == MediaProtocol.File &&
-            //   job.RunTimeTicks.HasValue &&
-            //   job.VideoType == VideoType.VideoFile &&
-            //   !string.Equals(job.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
-            //{
-            //    if (job.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && job.IsInputVideo)
-            //    {
-            //        if (SupportsThrottleWithStream)
-            //        {
-            //            var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/videos/" + job.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + job.Request.MediaSourceId;
-
-            //            url += "&transcodingJobId=" + transcodingJobId;
-
-            //            return string.Format("\"{0}\"", url);
-            //        }
-            //    }
-            //}
-
             var protocol = job.InputProtocol;
 
             var inputPath = new[] { job.MediaPath };
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
index 925d17bc68..c5783e1882 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
@@ -4,7 +4,6 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.MediaInfo;
@@ -23,15 +22,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
         private readonly ILiveTvManager _liveTvManager;
         private readonly ILibraryManager _libraryManager;
         private readonly IChannelManager _channelManager;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
         protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
         
-        public EncodingJobFactory(ILogger logger, ILiveTvManager liveTvManager, ILibraryManager libraryManager, IChannelManager channelManager)
+        public EncodingJobFactory(ILogger logger, ILiveTvManager liveTvManager, ILibraryManager libraryManager, IChannelManager channelManager, IMediaSourceManager mediaSourceManager)
         {
             _logger = logger;
             _liveTvManager = liveTvManager;
             _libraryManager = libraryManager;
             _channelManager = channelManager;
+            _mediaSourceManager = mediaSourceManager;
         }
 
         public async Task<EncodingJob> CreateJob(EncodingJobOptions options, bool isVideoRequest, IProgress<double> progress, CancellationToken cancellationToken)
@@ -71,10 +72,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
                 var path = recording.RecordingInfo.Path;
                 var mediaUrl = recording.RecordingInfo.Url;
-
+                
                 var source = string.IsNullOrEmpty(request.MediaSourceId)
                     ? recording.GetMediaSources(false).First()
-                    : recording.GetMediaSources(false).First(i => string.Equals(i.Id, request.MediaSourceId));
+                    : _mediaSourceManager.GetStaticMediaSource(recording, request.MediaSourceId, false);
 
                 mediaStreams = source.MediaStreams;
 
@@ -113,25 +114,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 // Just to prevent this from being null and causing other methods to fail
                 state.MediaPath = string.Empty;
             }
-            else if (item is IChannelMediaItem)
-            {
-                var mediaSource = await GetChannelMediaInfo(request.ItemId, request.MediaSourceId, cancellationToken).ConfigureAwait(false);
-                state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-                state.InputProtocol = mediaSource.Protocol;
-                state.MediaPath = mediaSource.Path;
-                state.RunTimeTicks = item.RunTimeTicks;
-                state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
-                state.InputBitrate = mediaSource.Bitrate;
-                state.InputFileSize = mediaSource.Size;
-                state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
-                mediaStreams = mediaSource.MediaStreams;
-            }
             else
             {
-                var hasMediaSources = (IHasMediaSources)item;
+                var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(request.ItemId, false, cancellationToken).ConfigureAwait(false);
+
                 var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
-                    ? hasMediaSources.GetMediaSources(false).First()
-                    : hasMediaSources.GetMediaSources(false).First(i => string.Equals(i.Id, request.MediaSourceId));
+                    ? mediaSources.First()
+                    : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
 
                 mediaStreams = mediaSource.MediaStreams;
 
@@ -141,6 +130,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 state.InputFileSize = mediaSource.Size;
                 state.InputBitrate = mediaSource.Bitrate;
                 state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+                state.RunTimeTicks = mediaSource.RunTimeTicks;
+                state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
 
                 var video = item as Video;
 
@@ -424,29 +415,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return bitrate;
         }
 
-        private async Task<MediaSourceInfo> GetChannelMediaInfo(string id,
-            string mediaSourceId,
-            CancellationToken cancellationToken)
-        {
-            var channelMediaSources = await _channelManager.GetChannelItemMediaSources(id, true, cancellationToken)
-                .ConfigureAwait(false);
-
-            var list = channelMediaSources.ToList();
-
-            if (!string.IsNullOrWhiteSpace(mediaSourceId))
-            {
-                var source = list
-                    .FirstOrDefault(i => string.Equals(mediaSourceId, i.Id));
-
-                if (source != null)
-                {
-                    return source;
-                }
-            }
-
-            return list.First();
-        }
-
         protected string GetVideoBitrateParam(EncodingJob state, string videoCodec, bool isHls)
         {
             var bitrate = state.OutputVideoBitrate;
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index b75d7bee30..7fd91bf6f8 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -70,8 +70,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
         protected readonly IChannelManager ChannelManager;
         protected readonly ISessionManager SessionManager;
         protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
+        protected readonly Func<IMediaSourceManager> MediaSourceManager;
 
-        public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder)
+        public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func<ISubtitleEncoder> subtitleEncoder, Func<IMediaSourceManager> mediaSourceManager)
         {
             _logger = logger;
             _jsonSerializer = jsonSerializer;
@@ -84,6 +85,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             ChannelManager = channelManager;
             SessionManager = sessionManager;
             SubtitleEncoder = subtitleEncoder;
+            MediaSourceManager = mediaSourceManager;
             FFProbePath = ffProbePath;
             FFMpegPath = ffMpegPath;
         }
@@ -580,7 +582,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 LibraryManager,
                 ChannelManager,
                 SessionManager,
-                SubtitleEncoder())
+                SubtitleEncoder(),
+                MediaSourceManager())
                 .Start(options, progress, cancellationToken).ConfigureAwait(false);
 
             await job.TaskCompletionSource.Task.ConfigureAwait(false);
@@ -601,7 +604,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 LibraryManager,
                 ChannelManager,
                 SessionManager,
-                SubtitleEncoder())
+                SubtitleEncoder(),
+                MediaSourceManager())
                 .Start(options, progress, cancellationToken).ConfigureAwait(false);
 
             await job.TaskCompletionSource.Task.ConfigureAwait(false);
diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
index 941649addc..efd0bd9098 100644
--- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
@@ -14,7 +14,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 {
     public class VideoEncoder : BaseEncoder
     {
-        public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder) : base(mediaEncoder, logger, configurationManager, fileSystem, liveTvManager, isoManager, libraryManager, channelManager, sessionManager, subtitleEncoder)
+        public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager) : base(mediaEncoder, logger, configurationManager, fileSystem, liveTvManager, isoManager, libraryManager, channelManager, sessionManager, subtitleEncoder, mediaSourceManager)
         {
         }
 
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
index f289449452..2a8c958b25 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
@@ -49,6 +49,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     trackInfo.TrackEvents.Add(subEvent);
                 }
             }
+            RemoteNativeFormatting(trackInfo);
             return trackInfo;
         }
 
@@ -69,5 +70,50 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                                                      };
             return result;
         }
+
+        /// <summary>
+        /// Credit: https://github.com/SubtitleEdit/subtitleedit/blob/master/src/Logic/SubtitleFormats/AdvancedSubStationAlpha.cs
+        /// </summary>
+        private void RemoteNativeFormatting(SubtitleTrackInfo subtitle)
+        {
+            foreach (var p in subtitle.TrackEvents)
+            {
+                int indexOfBegin = p.Text.IndexOf('{');
+                string pre = string.Empty;
+                while (indexOfBegin >= 0 && p.Text.IndexOf('}') > indexOfBegin)
+                {
+                    string s = p.Text.Substring(indexOfBegin);
+                    if (s.StartsWith("{\\an1}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an2}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an3}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an4}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an5}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an6}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an7}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an8}", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an9}", StringComparison.Ordinal))
+                    {
+                        pre = s.Substring(0, 6);
+                    }
+                    else if (s.StartsWith("{\\an1\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an2\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an3\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an4\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an5\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an6\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an7\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an8\\", StringComparison.Ordinal) ||
+                        s.StartsWith("{\\an9\\", StringComparison.Ordinal))
+                    {
+                        pre = s.Substring(0, 5) + "}";
+                    }
+                    int indexOfEnd = p.Text.IndexOf('}');
+                    p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1);
+
+                    indexOfBegin = p.Text.IndexOf('{');
+                }
+                p.Text = pre + p.Text;
+            }
+        }
     }
 }
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index b9cad27e0d..7d74c51bad 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -773,7 +773,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
         {
             try
             {
-                using (var file = new FileStream(path, FileMode.Open))
+                using (var file = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                 {
                     var detector = new CharsetDetector();
                     detector.Feed(file);
@@ -797,12 +797,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
             return null;
         }
 
-        private static Encoding GetFileEncoding(string srcFile)
+        private Encoding GetFileEncoding(string srcFile)
         {
             // *** Detect byte order mark if any - otherwise assume default
             var buffer = new byte[5];
 
-            using (var file = new FileStream(srcFile, FileMode.Open))
+            using (var file = _fileSystem.GetFileStream(srcFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
             {
                 file.Read(buffer, 0, 5);
             }
diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
index 37057f2d74..c2d46b9b3f 100644
--- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
+++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
@@ -356,12 +356,24 @@
     <Compile Include="..\MediaBrowser.Model\Dlna\HttpHeaderInfo.cs">
       <Link>Dlna\HttpHeaderInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\ILocalPlayer.cs">
+      <Link>Dlna\ILocalPlayer.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\MediaFormatProfile.cs">
       <Link>Dlna\MediaFormatProfile.cs</Link>
     </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\MediaFormatProfileResolver.cs">
       <Link>Dlna\MediaFormatProfileResolver.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\NullLocalPlayer.cs">
+      <Link>Dlna\NullLocalPlayer.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\PlaybackErrorCode.cs">
+      <Link>Dlna\PlaybackErrorCode.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\PlaybackException.cs">
+      <Link>Dlna\PlaybackException.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\ProfileCondition.cs">
       <Link>Dlna\ProfileCondition.cs</Link>
     </Compile>
@@ -479,6 +491,9 @@
     <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs">
       <Link>Dto\MetadataEditorInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dto\NameIdPair.cs">
+      <Link>Dto\NameIdPair.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs">
       <Link>Dto\NameValuePair.cs</Link>
     </Compile>
@@ -944,6 +959,9 @@
     <Compile Include="..\MediaBrowser.Model\Querying\LatestItemsQuery.cs">
       <Link>Querying\LatestItemsQuery.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Querying\MovieRecommendationQuery.cs">
+      <Link>Querying\MovieRecommendationQuery.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\NextUpQuery.cs">
       <Link>Querying\NextUpQuery.cs</Link>
     </Compile>
@@ -962,9 +980,6 @@
     <Compile Include="..\MediaBrowser.Model\Querying\SessionQuery.cs">
       <Link>Querying\SessionQuery.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsByNameQuery.cs">
-      <Link>Querying\SimilarItemsByNameQuery.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsQuery.cs">
       <Link>Querying\SimilarItemsQuery.cs</Link>
     </Compile>
@@ -977,6 +992,9 @@
     <Compile Include="..\MediaBrowser.Model\Querying\UserQuery.cs">
       <Link>Querying\UserQuery.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Registration\RegistrationInfo.cs">
+      <Link>Registration\RegistrationInfo.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Search\SearchHint.cs">
       <Link>Search\SearchHint.cs</Link>
     </Compile>
@@ -1061,6 +1079,12 @@
     <Compile Include="..\MediaBrowser.Model\Sync\LocalItem.cs">
       <Link>Sync\LocalItem.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Sync\LocalItemInfo.cs">
+      <Link>Sync\LocalItemInfo.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Sync\LocalItemQuery.cs">
+      <Link>Sync\LocalItemQuery.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\SyncCategory.cs">
       <Link>Sync\SyncCategory.cs</Link>
     </Compile>
@@ -1076,9 +1100,6 @@
     <Compile Include="..\MediaBrowser.Model\Sync\SyncedItem.cs">
       <Link>Sync\SyncedItem.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Sync\SyncHelper.cs">
-      <Link>Sync\SyncHelper.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\SyncJob.cs">
       <Link>Sync\SyncJob.cs</Link>
     </Compile>
@@ -1109,8 +1130,11 @@
     <Compile Include="..\MediaBrowser.Model\Sync\SyncParameter.cs">
       <Link>Sync\SyncParameter.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Sync\SyncQuality.cs">
-      <Link>Sync\SyncQuality.cs</Link>
+    <Compile Include="..\MediaBrowser.Model\Sync\SyncProfileOption.cs">
+      <Link>Sync\SyncProfileOption.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Sync\SyncQualityOption.cs">
+      <Link>Sync\SyncQualityOption.cs</Link>
     </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\SyncTarget.cs">
       <Link>Sync\SyncTarget.cs</Link>
diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
index f38a8f597b..52745b5dee 100644
--- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
+++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
@@ -321,12 +321,24 @@
     <Compile Include="..\MediaBrowser.Model\Dlna\HttpHeaderInfo.cs">
       <Link>Dlna\HttpHeaderInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\ILocalPlayer.cs">
+      <Link>Dlna\ILocalPlayer.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\MediaFormatProfile.cs">
       <Link>Dlna\MediaFormatProfile.cs</Link>
     </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\MediaFormatProfileResolver.cs">
       <Link>Dlna\MediaFormatProfileResolver.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\NullLocalPlayer.cs">
+      <Link>Dlna\NullLocalPlayer.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\PlaybackErrorCode.cs">
+      <Link>Dlna\PlaybackErrorCode.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dlna\PlaybackException.cs">
+      <Link>Dlna\PlaybackException.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\ProfileCondition.cs">
       <Link>Dlna\ProfileCondition.cs</Link>
     </Compile>
@@ -444,6 +456,9 @@
     <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs">
       <Link>Dto\MetadataEditorInfo.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Dto\NameIdPair.cs">
+      <Link>Dto\NameIdPair.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs">
       <Link>Dto\NameValuePair.cs</Link>
     </Compile>
@@ -639,9 +654,6 @@
     <Compile Include="..\MediaBrowser.Model\IO\IIsoMount.cs">
       <Link>IO\IIsoMount.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\IO\IZipClient.cs">
-      <Link>IO\IZipClient.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Library\PlayAccess.cs">
       <Link>Library\PlayAccess.cs</Link>
     </Compile>
@@ -903,6 +915,9 @@
     <Compile Include="..\MediaBrowser.Model\Querying\LatestItemsQuery.cs">
       <Link>Querying\LatestItemsQuery.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Querying\MovieRecommendationQuery.cs">
+      <Link>Querying\MovieRecommendationQuery.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\NextUpQuery.cs">
       <Link>Querying\NextUpQuery.cs</Link>
     </Compile>
@@ -921,9 +936,6 @@
     <Compile Include="..\MediaBrowser.Model\Querying\SessionQuery.cs">
       <Link>Querying\SessionQuery.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsByNameQuery.cs">
-      <Link>Querying\SimilarItemsByNameQuery.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Querying\SimilarItemsQuery.cs">
       <Link>Querying\SimilarItemsQuery.cs</Link>
     </Compile>
@@ -936,6 +948,9 @@
     <Compile Include="..\MediaBrowser.Model\Querying\UserQuery.cs">
       <Link>Querying\UserQuery.cs</Link>
     </Compile>
+    <Compile Include="..\mediabrowser.model\registration\RegistrationInfo.cs">
+      <Link>Registration\RegistrationInfo.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Search\SearchHint.cs">
       <Link>Search\SearchHint.cs</Link>
     </Compile>
@@ -1020,6 +1035,12 @@
     <Compile Include="..\MediaBrowser.Model\Sync\LocalItem.cs">
       <Link>Sync\LocalItem.cs</Link>
     </Compile>
+    <Compile Include="..\MediaBrowser.Model\Sync\LocalItemInfo.cs">
+      <Link>Sync\LocalItemInfo.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Sync\LocalItemQuery.cs">
+      <Link>Sync\LocalItemQuery.cs</Link>
+    </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\SyncCategory.cs">
       <Link>Sync\SyncCategory.cs</Link>
     </Compile>
@@ -1035,9 +1056,6 @@
     <Compile Include="..\MediaBrowser.Model\Sync\SyncedItem.cs">
       <Link>Sync\SyncedItem.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Sync\SyncHelper.cs">
-      <Link>Sync\SyncHelper.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\SyncJob.cs">
       <Link>Sync\SyncJob.cs</Link>
     </Compile>
@@ -1068,8 +1086,11 @@
     <Compile Include="..\MediaBrowser.Model\Sync\SyncParameter.cs">
       <Link>Sync\SyncParameter.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Sync\SyncQuality.cs">
-      <Link>Sync\SyncQuality.cs</Link>
+    <Compile Include="..\MediaBrowser.Model\Sync\SyncProfileOption.cs">
+      <Link>Sync\SyncProfileOption.cs</Link>
+    </Compile>
+    <Compile Include="..\MediaBrowser.Model\Sync\SyncQualityOption.cs">
+      <Link>Sync\SyncQualityOption.cs</Link>
     </Compile>
     <Compile Include="..\MediaBrowser.Model\Sync\SyncTarget.cs">
       <Link>Sync\SyncTarget.cs</Link>
diff --git a/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs b/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs
index b5bf299907..4ae4fe8223 100644
--- a/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs
+++ b/MediaBrowser.Model/ApiClient/ApiClientExtensions.cs
@@ -35,7 +35,14 @@ namespace MediaBrowser.Model.ApiClient
 
         public static Task<SyncDialogOptions> GetSyncOptions(this IApiClient apiClient, SyncJob job)
         {
-            return apiClient.GetSyncOptions(job.RequestedItemIds, job.UserId, job.ParentId, job.Category);
+            return apiClient.GetSyncOptions(new SyncJobRequest
+            {
+                Category = job.Category,
+                ItemIds = job.RequestedItemIds,
+                ParentId = job.ParentId,
+                TargetId = job.TargetId,
+                UserId = job.UserId
+            });
         }
     }
 }
diff --git a/MediaBrowser.Model/ApiClient/ConnectionOptions.cs b/MediaBrowser.Model/ApiClient/ConnectionOptions.cs
index 445eaa04ef..e12676311b 100644
--- a/MediaBrowser.Model/ApiClient/ConnectionOptions.cs
+++ b/MediaBrowser.Model/ApiClient/ConnectionOptions.cs
@@ -13,11 +13,17 @@ namespace MediaBrowser.Model.ApiClient
         /// </summary>
         /// <value><c>true</c> if [report capabilities]; otherwise, <c>false</c>.</value>
         public bool ReportCapabilities { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether [update date last accessed].
+        /// </summary>
+        /// <value><c>true</c> if [update date last accessed]; otherwise, <c>false</c>.</value>
+        public bool UpdateDateLastAccessed { get; set; }
 
         public ConnectionOptions()
         {
             EnableWebSocket = true;
             ReportCapabilities = true;
+            UpdateDateLastAccessed = true;
         }
     }
 }
diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs
index ca49c6c5ad..ef99e444f5 100644
--- a/MediaBrowser.Model/ApiClient/IApiClient.cs
+++ b/MediaBrowser.Model/ApiClient/IApiClient.cs
@@ -251,12 +251,12 @@ namespace MediaBrowser.Model.ApiClient
         Task<ItemsResult> GetAdditionalParts(string itemId, string userId);
 
         /// <summary>
-        /// Gets the live media information.
+        /// Gets the playback information.
         /// </summary>
         /// <param name="itemId">The item identifier.</param>
         /// <param name="userId">The user identifier.</param>
         /// <returns>Task&lt;LiveMediaInfoResult&gt;.</returns>
-        Task<LiveMediaInfoResult> GetLiveMediaInfo(string itemId, string userId);
+        Task<LiveMediaInfoResult> GetPlaybackInfo(string itemId, string userId);
 
         /// <summary>
         /// Gets the users async.
@@ -344,14 +344,14 @@ namespace MediaBrowser.Model.ApiClient
         /// </summary>
         /// <param name="query">The query.</param>
         /// <returns>Task{ItemsResult}.</returns>
-        Task<ItemsResult> GetInstantMixFromArtistAsync(SimilarItemsByNameQuery query);
+        Task<ItemsResult> GetInstantMixFromArtistAsync(SimilarItemsQuery query);
 
         /// <summary>
         /// Gets the instant mix from music genre async.
         /// </summary>
         /// <param name="query">The query.</param>
         /// <returns>Task{ItemsResult}.</returns>
-        Task<ItemsResult> GetInstantMixFromMusicGenreAsync(SimilarItemsByNameQuery query);
+        Task<ItemsResult> GetInstantMixFromMusicGenreAsync(SimilarItemsQuery query);
 
         /// <summary>
         /// Gets the similar movies async.
@@ -417,15 +417,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>Task{ItemsResult}.</returns>
         Task<ItemsResult> GetAlbumArtistsAsync(ArtistsQuery query);
 
-        /// <summary>
-        /// Gets a studio
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="userId">The user id.</param>
-        /// <returns>Task{BaseItemDto}.</returns>
-        /// <exception cref="ArgumentNullException">userId</exception>
-        Task<BaseItemDto> GetStudioAsync(string name, string userId);
-
         /// <summary>
         /// Gets the next up async.
         /// </summary>
@@ -494,15 +485,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>Task{BaseItemDto}.</returns>
         Task<BaseItemDto> GetGameGenreAsync(string name, string userId);
 
-        /// <summary>
-        /// Gets the artist async.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="userId">The user id.</param>
-        /// <returns>Task{BaseItemDto}.</returns>
-        /// <exception cref="ArgumentNullException">name</exception>
-        Task<BaseItemDto> GetArtistAsync(string name, string userId);
-
         /// <summary>
         /// Restarts the server.
         /// </summary>
@@ -1011,14 +993,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <exception cref="ArgumentNullException">item</exception>
         string GetPersonImageUrl(BaseItemPerson item, ImageOptions options);
 
-        /// <summary>
-        /// Gets an image url that can be used to download an image from the api
-        /// </summary>
-        /// <param name="year">The year.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        string GetYearImageUrl(int year, ImageOptions options);
-
         /// <summary>
         /// Gets an image url that can be used to download an image from the api
         /// </summary>
@@ -1044,24 +1018,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>System.String.</returns>
         string GetGameGenreImageUrl(string name, ImageOptions options);
 
-        /// <summary>
-        /// Gets an image url that can be used to download an image from the api
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        /// <exception cref="ArgumentNullException">name</exception>
-        string GetStudioImageUrl(string name, ImageOptions options);
-
-        /// <summary>
-        /// Gets the artist image URL.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="options">The options.</param>
-        /// <returns>System.String.</returns>
-        /// <exception cref="ArgumentNullException">name</exception>
-        string GetArtistImageUrl(string name, ImageOptions options);
-
         /// <summary>
         /// This is a helper to get a list of backdrop url's from a given ApiBaseItemWrapper. If the actual item does not have any backdrops it will return backdrops from the first parent that does.
         /// </summary>
@@ -1362,7 +1318,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         Task SendContextMessageAsync(string itemType, string itemId, string itemName, string context,
-            CancellationToken cancellationToken);
+            CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Gets the content upload history.
@@ -1380,7 +1336,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>Task.</returns>
         Task UploadFile(Stream stream,
             LocalFileInfo file,
-            CancellationToken cancellationToken);
+            CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Gets the devices options options.
@@ -1436,7 +1392,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="id">The identifier.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;Stream&gt;.</returns>
-        Task<Stream> GetSyncJobItemFile(string id, CancellationToken cancellationToken);
+        Task<Stream> GetSyncJobItemFile(string id, CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Gets the synchronize job item additional file.
@@ -1519,11 +1475,20 @@ namespace MediaBrowser.Model.ApiClient
         /// <summary>
         /// Gets the synchronize options.
         /// </summary>
-        /// <param name="userId">The user identifier.</param>
-        /// <param name="itemIds">The item ids.</param>
-        /// <param name="parentId">The parent identifier.</param>
-        /// <param name="category">The category.</param>
+        /// <param name="jobInfo">The job information.</param>
         /// <returns>Task&lt;SyncOptions&gt;.</returns>
-        Task<SyncDialogOptions> GetSyncOptions(IEnumerable<string> itemIds, string userId, string parentId = null, SyncCategory? category = null);
+        Task<SyncDialogOptions> GetSyncOptions(SyncJobRequest jobInfo);
+        /// <summary>
+        /// Gets the synchronize options.
+        /// </summary>
+        /// <param name="jobInfo">The job information.</param>
+        /// <returns>Task&lt;SyncDialogOptions&gt;.</returns>
+        Task<SyncDialogOptions> GetSyncOptions(SyncJob jobInfo);
+        /// <summary>
+        /// Gets the movie recommendations.
+        /// </summary>
+        /// <param name="query">The query.</param>
+        /// <returns>Task&lt;List&lt;RecommendationDto&gt;&gt;.</returns>
+        Task<List<RecommendationDto>> GetMovieRecommendations(MovieRecommendationQuery query);
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Model/ApiClient/IConnectionManager.cs b/MediaBrowser.Model/ApiClient/IConnectionManager.cs
index 341df27280..6ff48a044e 100644
--- a/MediaBrowser.Model/ApiClient/IConnectionManager.cs
+++ b/MediaBrowser.Model/ApiClient/IConnectionManager.cs
@@ -1,6 +1,7 @@
 using MediaBrowser.Model.Connect;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Events;
+using MediaBrowser.Model.Session;
 using System;
 using System.Collections.Generic;
 using System.Threading;
@@ -47,6 +48,12 @@ namespace MediaBrowser.Model.ApiClient
         /// <value><c>true</c> if [save local credentials]; otherwise, <c>false</c>.</value>
         bool SaveLocalCredentials { get; set; }
 
+        /// <summary>
+        /// Gets the client capabilities.
+        /// </summary>
+        /// <value>The client capabilities.</value>
+        ClientCapabilities ClientCapabilities { get; }
+
         /// <summary>
         /// Gets the API client.
         /// </summary>
@@ -66,7 +73,7 @@ namespace MediaBrowser.Model.ApiClient
         /// </summary>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;ConnectionResult&gt;.</returns>
-        Task<ConnectionResult> Connect(CancellationToken cancellationToken);
+        Task<ConnectionResult> Connect(CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Connects the specified API client.
@@ -74,7 +81,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="apiClient">The API client.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;ConnectionResult&gt;.</returns>
-        Task<ConnectionResult> Connect(IApiClient apiClient, CancellationToken cancellationToken);
+        Task<ConnectionResult> Connect(IApiClient apiClient, CancellationToken cancellationToken = default(CancellationToken));
         
         /// <summary>
         /// Connects the specified server.
@@ -82,7 +89,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="server">The server.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;ConnectionResult&gt;.</returns>
-        Task<ConnectionResult> Connect(ServerInfo server, CancellationToken cancellationToken);
+        Task<ConnectionResult> Connect(ServerInfo server, CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Connects the specified server.
@@ -91,7 +98,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;ConnectionResult&gt;.</returns>
-        Task<ConnectionResult> Connect(ServerInfo server, ConnectionOptions options, CancellationToken cancellationToken);
+        Task<ConnectionResult> Connect(ServerInfo server, ConnectionOptions options, CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Connects the specified server.
@@ -99,7 +106,7 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="address">The address.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;ConnectionResult&gt;.</returns>
-        Task<ConnectionResult> Connect(string address, CancellationToken cancellationToken);
+        Task<ConnectionResult> Connect(string address, CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Logouts this instance.
@@ -138,11 +145,18 @@ namespace MediaBrowser.Model.ApiClient
         /// <returns>Task.</returns>
         Task ExchangePin(PinCreationResult pin);
 
+        /// <summary>
+        /// Gets the server information.
+        /// </summary>
+        /// <param name="id">The identifier.</param>
+        /// <returns>Task&lt;ServerInfo&gt;.</returns>
+        Task<ServerInfo> GetServerInfo(string id);
+
         /// <summary>
         /// Gets the available servers.
         /// </summary>
         /// <param name="cancellationToken">The cancellation token.</param>
-        Task<List<ServerInfo>> GetAvailableServers(CancellationToken cancellationToken);
+        Task<List<ServerInfo>> GetAvailableServers(CancellationToken cancellationToken = default(CancellationToken));
 
         /// <summary>
         /// Authenticates an offline user with their password
diff --git a/MediaBrowser.Model/ApiClient/IDevice.cs b/MediaBrowser.Model/ApiClient/IDevice.cs
index 84927c20a9..7b67122fb8 100644
--- a/MediaBrowser.Model/ApiClient/IDevice.cs
+++ b/MediaBrowser.Model/ApiClient/IDevice.cs
@@ -39,6 +39,6 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="apiClient">The API client.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task UploadFile(LocalFileInfo file, IApiClient apiClient, CancellationToken cancellationToken);
+        Task UploadFile(LocalFileInfo file, IApiClient apiClient, CancellationToken cancellationToken = default(CancellationToken));
     }
 }
diff --git a/MediaBrowser.Model/Configuration/DlnaOptions.cs b/MediaBrowser.Model/Configuration/DlnaOptions.cs
index df7ae5c49c..277102a501 100644
--- a/MediaBrowser.Model/Configuration/DlnaOptions.cs
+++ b/MediaBrowser.Model/Configuration/DlnaOptions.cs
@@ -10,6 +10,7 @@ namespace MediaBrowser.Model.Configuration
         public int ClientDiscoveryIntervalSeconds { get; set; }
         public int BlastAliveMessageIntervalSeconds { get; set; }
         public string DefaultUserId { get; set; }
+        public bool EnableEnhancedMovies { get; set; }
 
         public DlnaOptions()
         {
@@ -18,6 +19,7 @@ namespace MediaBrowser.Model.Configuration
             BlastAliveMessages = true;
             ClientDiscoveryIntervalSeconds = 60;
             BlastAliveMessageIntervalSeconds = 30;
+            EnableEnhancedMovies = true;
         }
     }
 }
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index a28d3bd5db..c06aedb500 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -44,6 +44,12 @@ namespace MediaBrowser.Model.Configuration
         /// <value><c>true</c> if [use HTTPS]; otherwise, <c>false</c>.</value>
         public bool EnableHttps { get; set; }
 
+        /// <summary>
+        /// Gets or sets a value indicating whether [enable user specific user views].
+        /// </summary>
+        /// <value><c>true</c> if [enable user specific user views]; otherwise, <c>false</c>.</value>
+        public bool EnableUserSpecificUserViews { get; set; }
+        
         /// <summary>
         /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..
         /// </summary>
@@ -203,8 +209,6 @@ namespace MediaBrowser.Model.Configuration
         public bool EnableAudioArchiveFiles { get; set; }
         public bool EnableVideoArchiveFiles { get; set; }
 
-        public bool EnableLegacyCollectionInView { get; set; }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index aa49ee50d5..a78161140f 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -33,20 +33,12 @@ namespace MediaBrowser.Model.Configuration
         public bool DisplayMissingEpisodes { get; set; }
         public bool DisplayUnairedEpisodes { get; set; }
 
-        public bool EnableLiveTvManagement { get; set; }
-        public bool EnableLiveTvAccess { get; set; }
-
-        public bool EnableMediaPlayback { get; set; }
-        public bool EnableContentDeletion { get; set; }
-
         public bool GroupMoviesIntoBoxSets { get; set; }
 
         public string[] DisplayChannelsWithinViews { get; set; }
 
         public string[] ExcludeFoldersFromGrouping { get; set; }
 
-        public UnratedItem[] BlockUnratedItems { get; set; }
-
         public SubtitlePlaybackMode SubtitleMode { get; set; }
         public bool DisplayCollectionsView { get; set; }
         public bool DisplayFoldersView { get; set; }
@@ -69,14 +61,10 @@ namespace MediaBrowser.Model.Configuration
         public UserConfiguration()
         {
             PlayDefaultAudioTrack = true;
-            EnableLiveTvManagement = true;
-            EnableMediaPlayback = true;
-            EnableLiveTvAccess = true;
 
             LatestItemsExcludes = new string[] { };
             OrderedViews = new string[] { };
             DisplayChannelsWithinViews = new string[] { };
-            BlockUnratedItems = new UnratedItem[] { };
 
             ExcludeFoldersFromGrouping = new string[] { };
             DisplayCollectionsView = true;
diff --git a/MediaBrowser.Model/Devices/DeviceInfo.cs b/MediaBrowser.Model/Devices/DeviceInfo.cs
index e5efe9f605..726e9d6e52 100644
--- a/MediaBrowser.Model/Devices/DeviceInfo.cs
+++ b/MediaBrowser.Model/Devices/DeviceInfo.cs
@@ -46,6 +46,11 @@ namespace MediaBrowser.Model.Devices
         /// <value>The name of the application.</value>
         public string AppName { get; set; }
         /// <summary>
+        /// Gets or sets the application version.
+        /// </summary>
+        /// <value>The application version.</value>
+        public string AppVersion { get; set; }
+        /// <summary>
         /// Gets or sets the last user identifier.
         /// </summary>
         /// <value>The last user identifier.</value>
diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs
index cddfd89559..6ad4fa2659 100644
--- a/MediaBrowser.Model/Dlna/AudioOptions.cs
+++ b/MediaBrowser.Model/Dlna/AudioOptions.cs
@@ -46,17 +46,6 @@ namespace MediaBrowser.Model.Dlna
         /// </summary>
         /// <value>The audio transcoding bitrate.</value>
         public int? AudioTranscodingBitrate { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether [supports direct remote content].
-        /// </summary>
-        /// <value><c>true</c> if [supports direct remote content]; otherwise, <c>false</c>.</value>
-        public bool SupportsDirectRemoteContent { get; set; }
-        /// <summary>
-        /// Gets or sets a value indicating whether [supports custom HTTP headers].
-        /// </summary>
-        /// <value><c>true</c> if [supports custom HTTP headers]; otherwise, <c>false</c>.</value>
-        public bool SupportsCustomHttpHeaders { get; set; }
         
         /// <summary>
         /// Gets the maximum bitrate.
diff --git a/MediaBrowser.Model/Dlna/ILocalPlayer.cs b/MediaBrowser.Model/Dlna/ILocalPlayer.cs
new file mode 100644
index 0000000000..55e11ec4b7
--- /dev/null
+++ b/MediaBrowser.Model/Dlna/ILocalPlayer.cs
@@ -0,0 +1,26 @@
+
+namespace MediaBrowser.Model.Dlna
+{
+    public interface ILocalPlayer
+    {
+        /// <summary>
+        /// Determines whether this instance [can access file] the specified path.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns><c>true</c> if this instance [can access file] the specified path; otherwise, <c>false</c>.</returns>
+        bool CanAccessFile(string path);
+        /// <summary>
+        /// Determines whether this instance [can access directory] the specified path.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns><c>true</c> if this instance [can access directory] the specified path; otherwise, <c>false</c>.</returns>
+        bool CanAccessDirectory(string path);
+        /// <summary>
+        /// Determines whether this instance [can access URL] the specified URL.
+        /// </summary>
+        /// <param name="url">The URL.</param>
+        /// <param name="requiresCustomRequestHeaders">if set to <c>true</c> [requires custom request headers].</param>
+        /// <returns><c>true</c> if this instance [can access URL] the specified URL; otherwise, <c>false</c>.</returns>
+        bool CanAccessUrl(string url, bool requiresCustomRequestHeaders);
+    }
+}
diff --git a/MediaBrowser.Model/Dlna/NullLocalPlayer.cs b/MediaBrowser.Model/Dlna/NullLocalPlayer.cs
new file mode 100644
index 0000000000..c34b638871
--- /dev/null
+++ b/MediaBrowser.Model/Dlna/NullLocalPlayer.cs
@@ -0,0 +1,21 @@
+
+namespace MediaBrowser.Model.Dlna
+{
+    public class NullLocalPlayer : ILocalPlayer
+    {
+        public bool CanAccessFile(string path)
+        {
+            return false;
+        }
+
+        public bool CanAccessDirectory(string path)
+        {
+            return false;
+        }
+
+        public bool CanAccessUrl(string url, bool requiresCustomRequestHeaders)
+        {
+            return false;
+        }
+    }
+}
diff --git a/MediaBrowser.Model/Dlna/PlaybackErrorCode.cs b/MediaBrowser.Model/Dlna/PlaybackErrorCode.cs
new file mode 100644
index 0000000000..4ed4129854
--- /dev/null
+++ b/MediaBrowser.Model/Dlna/PlaybackErrorCode.cs
@@ -0,0 +1,10 @@
+
+namespace MediaBrowser.Model.Dlna
+{
+    public enum PlaybackErrorCode
+    {
+        NotAllowed = 0,
+        NoCompatibleStream = 1,
+        RateLimitExceeded = 2
+    }
+}
diff --git a/MediaBrowser.Model/Dlna/PlaybackException.cs b/MediaBrowser.Model/Dlna/PlaybackException.cs
new file mode 100644
index 0000000000..761fa1c904
--- /dev/null
+++ b/MediaBrowser.Model/Dlna/PlaybackException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace MediaBrowser.Model.Dlna
+{
+    public class PlaybackException : Exception
+    {
+        public PlaybackErrorCode ErrorCode { get; set;}
+    }
+}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 6fa29a533b..6edbe00daf 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -10,28 +10,40 @@ namespace MediaBrowser.Model.Dlna
 {
     public class StreamBuilder
     {
+        private readonly ILocalPlayer _localPlayer;
+
+        public StreamBuilder(ILocalPlayer localPlayer)
+        {
+            _localPlayer = localPlayer;
+        }
+        public StreamBuilder()
+            : this(new NullLocalPlayer())
+        {
+        }
+
         public StreamInfo BuildAudioItem(AudioOptions options)
         {
             ValidateAudioInput(options);
 
-            List<MediaSourceInfo> mediaSources = options.MediaSources;
-
-            // If the client wants a specific media source, filter now
-            if (!string.IsNullOrEmpty(options.MediaSourceId))
+            List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>();
+            foreach (MediaSourceInfo i in options.MediaSources)
             {
-                List<MediaSourceInfo> newMediaSources = new List<MediaSourceInfo>();
-                foreach (MediaSourceInfo i in mediaSources)
+                if (string.IsNullOrEmpty(options.MediaSourceId) ||
+                    StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
                 {
-                    if (StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
-                        newMediaSources.Add(i);
+                    mediaSources.Add(i);
                 }
-
-                mediaSources = newMediaSources;
             }
 
             List<StreamInfo> streams = new List<StreamInfo>();
             foreach (MediaSourceInfo i in mediaSources)
-                streams.Add(BuildAudioItem(i, options));
+            {
+                StreamInfo streamInfo = BuildAudioItem(i, options);
+                if (streamInfo != null)
+                {
+                    streams.Add(streamInfo);
+                }
+            }
 
             foreach (StreamInfo stream in streams)
             {
@@ -46,24 +58,25 @@ namespace MediaBrowser.Model.Dlna
         {
             ValidateInput(options);
 
-            List<MediaSourceInfo> mediaSources = options.MediaSources;
-
-            // If the client wants a specific media source, filter now
-            if (!string.IsNullOrEmpty(options.MediaSourceId))
+            List<MediaSourceInfo> mediaSources = new List<MediaSourceInfo>();
+            foreach (MediaSourceInfo i in options.MediaSources)
             {
-                List<MediaSourceInfo> newMediaSources = new List<MediaSourceInfo>();
-                foreach (MediaSourceInfo i in mediaSources)
+                if (string.IsNullOrEmpty(options.MediaSourceId) ||
+                    StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
                 {
-                    if (StringHelper.EqualsIgnoreCase(i.Id, options.MediaSourceId))
-                        newMediaSources.Add(i);
+                    mediaSources.Add(i);
                 }
-
-                mediaSources = newMediaSources;
             }
 
             List<StreamInfo> streams = new List<StreamInfo>();
             foreach (MediaSourceInfo i in mediaSources)
-                streams.Add(BuildVideoItem(i, options));
+            {
+                StreamInfo streamInfo = BuildVideoItem(i, options);
+                if (streamInfo != null)
+                {
+                    streams.Add(streamInfo);
+                }
+            }
 
             foreach (StreamInfo stream in streams)
             {
@@ -97,7 +110,10 @@ namespace MediaBrowser.Model.Dlna
             {
                 return stream;
             }
-            return null;
+
+            PlaybackException error = new PlaybackException();
+            error.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
+            throw error;
         }
 
         private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
@@ -112,64 +128,66 @@ namespace MediaBrowser.Model.Dlna
                 DeviceProfile = options.Profile
             };
 
-            int? maxBitrateSetting = options.GetMaxBitrate();
-
-            MediaStream audioStream = item.DefaultAudioStream;
+            List<PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, options);
 
-            // Honor the max bitrate setting
-            if (IsAudioEligibleForDirectPlay(item, maxBitrateSetting))
+            if (directPlayMethods.Count > 0)
             {
-                DirectPlayProfile directPlay = null;
-                foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
-                {
-                    if (i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream))
-                    {
-                        directPlay = i;
-                        break;
-                    }
-                }
+                MediaStream audioStream = item.DefaultAudioStream;
 
-                if (directPlay != null)
+                string audioCodec = audioStream == null ? null : audioStream.Codec;
+
+                // Make sure audio codec profiles are satisfied
+                if (!string.IsNullOrEmpty(audioCodec))
                 {
-                    string audioCodec = audioStream == null ? null : audioStream.Codec;
+                    ConditionProcessor conditionProcessor = new ConditionProcessor();
 
-                    // Make sure audio codec profiles are satisfied
-                    if (!string.IsNullOrEmpty(audioCodec))
+                    List<ProfileCondition> conditions = new List<ProfileCondition>();
+                    foreach (CodecProfile i in options.Profile.CodecProfiles)
                     {
-                        ConditionProcessor conditionProcessor = new ConditionProcessor();
-
-                        List<ProfileCondition> conditions = new List<ProfileCondition>();
-                        foreach (CodecProfile i in options.Profile.CodecProfiles)
+                        if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
                         {
-                            if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
+                            foreach (ProfileCondition c in i.Conditions)
                             {
-                                foreach (ProfileCondition c in i.Conditions)
-                                {
-                                    conditions.Add(c);
-                                }
+                                conditions.Add(c);
                             }
                         }
+                    }
 
-                        int? audioChannels = audioStream.Channels;
-                        int? audioBitrate = audioStream.BitRate;
+                    int? audioChannels = audioStream.Channels;
+                    int? audioBitrate = audioStream.BitRate;
 
-                        bool all = true;
-                        foreach (ProfileCondition c in conditions)
+                    bool all = true;
+                    foreach (ProfileCondition c in conditions)
+                    {
+                        if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate))
                         {
-                            if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate))
-                            {
-                                all = false;
-                                break;
-                            }
+                            all = false;
+                            break;
                         }
+                    }
 
-                        if (all)
+                    if (all)
+                    {
+                        if (item.Protocol == MediaProtocol.File &&
+                            directPlayMethods.Contains(PlayMethod.DirectPlay) && 
+                            _localPlayer.CanAccessFile(item.Path))
+                        {
+                            playlistItem.PlayMethod = PlayMethod.DirectPlay;
+                        }
+                        else if (item.Protocol == MediaProtocol.Http &&
+                            directPlayMethods.Contains(PlayMethod.DirectPlay) &&
+                            _localPlayer.CanAccessUrl(item.Path, item.RequiredHttpHeaders.Count > 0))
+                        {
+                            playlistItem.PlayMethod = PlayMethod.DirectPlay;
+                        }
+                        else if (directPlayMethods.Contains(PlayMethod.DirectStream))
                         {
                             playlistItem.PlayMethod = PlayMethod.DirectStream;
-                            playlistItem.Container = item.Container;
-
-                            return playlistItem;
                         }
+
+                        playlistItem.Container = item.Container;
+
+                        return playlistItem;
                     }
                 }
             }
@@ -186,6 +204,11 @@ namespace MediaBrowser.Model.Dlna
 
             if (transcodingProfile != null)
             {
+                if (!item.SupportsTranscoding)
+                {
+                    return null;
+                }
+
                 playlistItem.PlayMethod = PlayMethod.Transcode;
                 playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
                 playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength;
@@ -233,6 +256,41 @@ namespace MediaBrowser.Model.Dlna
             return playlistItem;
         }
 
+        private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, AudioOptions options)
+        {
+            MediaStream audioStream = item.DefaultAudioStream;
+            
+            DirectPlayProfile directPlayProfile = null;
+            foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles)
+            {
+                if (i.Type == DlnaProfileType.Audio && IsAudioDirectPlaySupported(i, item, audioStream))
+                {
+                    directPlayProfile = i;
+                    break;
+                }
+            }
+
+            List<PlayMethod> playMethods = new List<PlayMethod>();
+
+            if (directPlayProfile != null)
+            {
+                // While options takes the network and other factors into account. Only applies to direct stream
+                if (item.SupportsDirectStream && IsAudioEligibleForDirectPlay(item, options.GetMaxBitrate()))
+                {
+                    playMethods.Add(PlayMethod.DirectStream);
+                }
+                
+                // The profile describes what the device supports
+                // If device requirements are satisfied then allow both direct stream and direct play
+                if (IsAudioEligibleForDirectPlay(item, options.Profile.MaxStaticBitrate))
+                {
+                    playMethods.Add(PlayMethod.DirectPlay);
+                }
+            }
+
+            return playMethods;
+        }
+
         private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options)
         {
             StreamInfo playlistItem = new StreamInfo
@@ -267,7 +325,7 @@ namespace MediaBrowser.Model.Dlna
 
                     if (subtitleStream != null)
                     {
-                        SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile);
+                        SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context);
 
                         playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
                         playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -290,9 +348,14 @@ namespace MediaBrowser.Model.Dlna
 
             if (transcodingProfile != null)
             {
+                if (!item.SupportsTranscoding)
+                {
+                    return null;
+                }
+
                 if (subtitleStream != null)
                 {
-                    SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile);
+                    SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context);
 
                     playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
                     playlistItem.SubtitleFormat = subtitleProfile.Format;
@@ -505,18 +568,25 @@ namespace MediaBrowser.Model.Dlna
 
             if (mediaSource.Protocol == MediaProtocol.Http)
             {
-                if (!options.SupportsDirectRemoteContent)
+                if (_localPlayer.CanAccessUrl(mediaSource.Path, mediaSource.RequiredHttpHeaders.Count > 0))
                 {
-                    return null;
+                    return PlayMethod.DirectPlay;
                 }
+            }
 
-                if (mediaSource.RequiredHttpHeaders.Count > 0 && !options.SupportsCustomHttpHeaders)
+            else if (mediaSource.Protocol == MediaProtocol.File)
+            {
+                if (_localPlayer.CanAccessFile(mediaSource.Path))
                 {
-                    return null;
+                    return PlayMethod.DirectPlay;
                 }
-                return PlayMethod.DirectPlay;
             }
 
+            if (!mediaSource.SupportsDirectStream)
+            {
+                return null;
+            }
+            
             return PlayMethod.DirectStream;
         }
 
@@ -527,7 +597,7 @@ namespace MediaBrowser.Model.Dlna
         {
             if (subtitleStream != null)
             {
-                SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile);
+                SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context);
 
                 if (subtitleProfile.Method != SubtitleDeliveryMethod.External && subtitleProfile.Method != SubtitleDeliveryMethod.Embed)
                 {
@@ -538,14 +608,20 @@ namespace MediaBrowser.Model.Dlna
             return IsAudioEligibleForDirectPlay(item, maxBitrate);
         }
 
-        public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, DeviceProfile deviceProfile)
+        public static SubtitleProfile GetSubtitleProfile(MediaStream subtitleStream, DeviceProfile deviceProfile, EncodingContext context)
         {
             // Look for an external profile that matches the stream type (text/graphical)
             foreach (SubtitleProfile profile in deviceProfile.SubtitleProfiles)
             {
-                if (subtitleStream.SupportsExternalStream)
+                if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
                 {
-                    if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
+                    if (subtitleStream.SupportsExternalStream)
+                    {
+                        return profile;
+                    }
+
+                    // For sync we can handle the longer extraction times
+                    if (context == EncodingContext.Static && subtitleStream.IsTextSubtitleStream)
                     {
                         return profile;
                     }
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 57a3899d4d..9e75619672 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -262,7 +262,7 @@ namespace MediaBrowser.Model.Dlna
 
         private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream)
         {
-            SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, DeviceProfile);
+            SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, DeviceProfile, Context);
 
             if (subtitleProfile.Method != SubtitleDeliveryMethod.External)
             {
@@ -617,5 +617,30 @@ namespace MediaBrowser.Model.Dlna
                 return MaxHeight;
             }
         }
+
+        public List<MediaStream> GetSelectableAudioStreams()
+        {
+            return GetSelectableStreams(MediaStreamType.Audio);
+        }
+
+        public List<MediaStream> GetSelectableSubtitleStreams()
+        {
+            return GetSelectableStreams(MediaStreamType.Subtitle);
+        }
+
+        public List<MediaStream> GetSelectableStreams(MediaStreamType type)
+        {
+            List<MediaStream> list = new List<MediaStream>();
+
+            foreach (MediaStream stream in MediaSource.MediaStreams)
+            {
+                if (type == stream.Type)
+                {
+                    list.Add(stream);
+                }
+            }
+
+            return list;
+        }
     }
 }
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index be3cd99be8..7a1c78112f 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -67,6 +67,7 @@ namespace MediaBrowser.Model.Dto
         public float? Metascore { get; set; }
 
         public bool? IsUnidentified { get; set; }
+        public bool? HasDynamicCategories { get; set; }
 
         public int? AnimeSeriesIndex { get; set; }
 
@@ -465,6 +466,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The artists.</value>
         public List<string> Artists { get; set; }
 
+        /// <summary>
+        /// Gets or sets the artist items.
+        /// </summary>
+        /// <value>The artist items.</value>
+        public List<NameIdPair> ArtistItems { get; set; }
+
         /// <summary>
         /// Gets or sets the album.
         /// </summary>
@@ -506,6 +513,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The album artist.</value>
         public string AlbumArtist { get; set; }
 
+        /// <summary>
+        /// Gets or sets the album artists.
+        /// </summary>
+        /// <value>The album artists.</value>
+        public List<NameIdPair> AlbumArtists { get; set; }
+        
         /// <summary>
         /// Gets or sets the name of the season.
         /// </summary>
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index 068443238b..3a9c1e7d4f 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -22,6 +22,8 @@ namespace MediaBrowser.Model.Dto
 
         public long? RunTimeTicks { get; set; }
         public bool ReadAtNativeFramerate { get; set; }
+        public bool SupportsTranscoding { get; set; }
+        public bool SupportsDirectStream { get; set; }
 
         public VideoType? VideoType { get; set; }
 
@@ -45,6 +47,8 @@ namespace MediaBrowser.Model.Dto
             MediaStreams = new List<MediaStream>();
             RequiredHttpHeaders = new Dictionary<string, string>();
             PlayableStreamFileNames = new List<string>();
+            SupportsTranscoding = true;
+            SupportsDirectStream = true;
         }
 
         public int? DefaultAudioStreamIndex { get; set; }
diff --git a/MediaBrowser.Model/Dto/NameIdPair.cs b/MediaBrowser.Model/Dto/NameIdPair.cs
new file mode 100644
index 0000000000..d3931516cd
--- /dev/null
+++ b/MediaBrowser.Model/Dto/NameIdPair.cs
@@ -0,0 +1,17 @@
+
+namespace MediaBrowser.Model.Dto
+{
+    public class NameIdPair
+    {
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+        /// <summary>
+        /// Gets or sets the identifier.
+        /// </summary>
+        /// <value>The identifier.</value>
+        public string Id { get; set; }
+    }
+}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvInfo.cs
index dd31c5a6bd..f4d3e21d98 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvInfo.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvInfo.cs
@@ -10,12 +10,6 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The services.</value>
         public List<LiveTvServiceInfo> Services { get; set; }
 
-        /// <summary>
-        /// Gets or sets the name of the active service.
-        /// </summary>
-        /// <value>The name of the active service.</value>
-        public string ActiveServiceName { get; set; }
-
         /// <summary>
         /// Gets or sets a value indicating whether this instance is enabled.
         /// </summary>
@@ -28,18 +22,6 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The enabled users.</value>
         public List<string> EnabledUsers { get; set; }
 
-        /// <summary>
-        /// Gets or sets the status.
-        /// </summary>
-        /// <value>The status.</value>
-        public LiveTvServiceStatus Status { get; set; }
-
-        /// <summary>
-        /// Gets or sets the status message.
-        /// </summary>
-        /// <value>The status message.</value>
-        public string StatusMessage { get; set; }
-
         public LiveTvInfo()
         {
             Services = new List<LiveTvServiceInfo>();
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 05fdc00b12..c6f6ed84ce 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -3,6 +3,11 @@
     public class LiveTvOptions
     {
         public int? GuideDays { get; set; }
-        public string ActiveService { get; set; }
+        public bool EnableMovieProviders { get; set; }
+
+        public LiveTvOptions()
+        {
+            EnableMovieProviders = true;
+        }
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/ProgramInfoDto.cs b/MediaBrowser.Model/LiveTv/ProgramInfoDto.cs
index f511a7a174..06136459ff 100644
--- a/MediaBrowser.Model/LiveTv/ProgramInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramInfoDto.cs
@@ -95,7 +95,13 @@ namespace MediaBrowser.Model.LiveTv
         /// </summary>
         /// <value>The official rating.</value>
         public string OfficialRating { get; set; }
-        
+
+        /// <summary>
+        /// Gets or sets the production year.
+        /// </summary>
+        /// <value>The production year.</value>
+        public int? ProductionYear { get; set; }
+
         /// <summary>
         /// Gets or sets the name of the service.
         /// </summary>
diff --git a/MediaBrowser.Model/LiveTv/ProgramQuery.cs b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
index 36c06d4c08..bbd396c33f 100644
--- a/MediaBrowser.Model/LiveTv/ProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/ProgramQuery.cs
@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Model.Entities;
+using System;
 
 namespace MediaBrowser.Model.LiveTv
 {
@@ -7,11 +8,18 @@ namespace MediaBrowser.Model.LiveTv
     /// </summary>
     public class ProgramQuery
     {
+        public ProgramQuery()
+        {
+            ChannelIds = new string[] { };
+            SortBy = new string[] { };
+            Genres = new string[] { };
+        }
+
         /// <summary>
-        /// Gets or sets the channel identifier.
+        /// Gets or sets the channel ids.
         /// </summary>
-        /// <value>The channel identifier.</value>
-        public string[] ChannelIdList { get; set; }
+        /// <value>The channel ids.</value>
+        public string[] ChannelIds { get; set; }
 
         /// <summary>
         /// Gets or sets the user identifier.
@@ -19,17 +27,64 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The user identifier.</value>
         public string UserId { get; set; }
 
+        /// <summary>
+        /// The earliest date for which a program starts to return
+        /// </summary>
         public DateTime? MinStartDate { get; set; }
 
+        /// <summary>
+        /// The latest date for which a program starts to return
+        /// </summary>
         public DateTime? MaxStartDate { get; set; }
 
+        /// <summary>
+        /// The earliest date for which a program ends to return
+        /// </summary>
         public DateTime? MinEndDate { get; set; }
 
+        /// <summary>
+        /// The latest date for which a program ends to return
+        /// </summary>
         public DateTime? MaxEndDate { get; set; }
-        
-        public ProgramQuery()
-        {
-            ChannelIdList = new string[] { };
-        }
+
+        /// <summary>
+        /// Used to specific whether to return movies or not
+        /// </summary>
+        /// <remarks>If set to null, all programs will be returned</remarks>
+        public bool? IsMovie { get; set; }
+
+        /// <summary>
+        /// Skips over a given number of items within the results. Use for paging.
+        /// </summary>
+        public int? StartIndex { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance has aired.
+        /// </summary>
+        /// <value><c>null</c> if [has aired] contains no value, <c>true</c> if [has aired]; otherwise, <c>false</c>.</value>
+        public bool? HasAired { get; set; }
+
+        /// <summary>
+        /// The maximum number of items to return
+        /// </summary>
+        public int? Limit { get; set; }
+
+        /// <summary>
+        /// What to sort the results by
+        /// </summary>
+        /// <value>The sort by.</value>
+        public string[] SortBy { get; set; }
+
+        /// <summary>
+        /// The sort order to return results with
+        /// </summary>
+        /// <value>The sort order.</value>
+        public SortOrder? SortOrder { get; set; }
+
+        /// <summary>
+        /// Limit results to items containing specific genres
+        /// </summary>
+        /// <value>The genres.</value>
+        public string[] Genres { get; set; }
     }
-}
+}
\ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
index 907902123e..9ba8e0e5fc 100644
--- a/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecommendedProgramQuery.cs
@@ -25,5 +25,11 @@
         /// </summary>
         /// <value>The limit.</value>
         public int? Limit { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is movie.
+        /// </summary>
+        /// <value><c>null</c> if [is movie] contains no value, <c>true</c> if [is movie]; otherwise, <c>false</c>.</value>
+        public bool? IsMovie { get; set; }
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
index a6cd85d8d3..d6d6980381 100644
--- a/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingInfoDto.cs
@@ -273,6 +273,10 @@ namespace MediaBrowser.Model.LiveTv
         /// <value>The type.</value>
         public string Type { get; set; }
 
+        /// <summary>
+        /// Gets or sets the media sources.
+        /// </summary>
+        /// <value>The media sources.</value>
         public List<MediaSourceInfo> MediaSources { get; set; }
         
         public RecordingInfoDto()
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index 9fd632cbd0..3a6eda6207 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -125,6 +125,10 @@
     <Compile Include="Devices\DeviceInfo.cs" />
     <Compile Include="Devices\DevicesOptions.cs" />
     <Compile Include="Dlna\EncodingContext.cs" />
+    <Compile Include="Dlna\ILocalPlayer.cs" />
+    <Compile Include="Dlna\NullLocalPlayer.cs" />
+    <Compile Include="Dlna\PlaybackErrorCode.cs" />
+    <Compile Include="Dlna\PlaybackException.cs" />
     <Compile Include="Dlna\Profiles\DefaultProfile.cs" />
     <Compile Include="Dlna\ResolutionConfiguration.cs" />
     <Compile Include="Dlna\ResolutionNormalizer.cs" />
@@ -134,6 +138,7 @@
     <Compile Include="Drawing\ImageOrientation.cs" />
     <Compile Include="Dto\IHasServerId.cs" />
     <Compile Include="Dto\MetadataEditorInfo.cs" />
+    <Compile Include="Dto\NameIdPair.cs" />
     <Compile Include="Dto\NameValuePair.cs" />
     <Compile Include="MediaInfo\LiveMediaInfoResult.cs" />
     <Compile Include="Dto\MediaSourceType.cs" />
@@ -310,15 +315,16 @@
     <Compile Include="Querying\ItemsByNameQuery.cs" />
     <Compile Include="Entities\BaseItemInfo.cs" />
     <Compile Include="Querying\LatestItemsQuery.cs" />
+    <Compile Include="Querying\MovieRecommendationQuery.cs" />
     <Compile Include="Querying\NextUpQuery.cs" />
     <Compile Include="Querying\QueryFilters.cs" />
     <Compile Include="Querying\QueryResult.cs" />
     <Compile Include="Querying\SeasonQuery.cs" />
     <Compile Include="Querying\SessionQuery.cs" />
-    <Compile Include="Querying\SimilarItemsByNameQuery.cs" />
     <Compile Include="Querying\SimilarItemsQuery.cs" />
     <Compile Include="Querying\UpcomingEpisodesQuery.cs" />
     <Compile Include="Querying\UserQuery.cs" />
+    <Compile Include="Registration\RegistrationInfo.cs" />
     <Compile Include="Search\SearchQuery.cs" />
     <Compile Include="Session\BrowseRequest.cs" />
     <Compile Include="Session\ClientCapabilities.cs" />
@@ -374,12 +380,13 @@
     <Compile Include="Sync\ItemFIleInfo.cs" />
     <Compile Include="Sync\ItemFileType.cs" />
     <Compile Include="Sync\LocalItem.cs" />
+    <Compile Include="Sync\LocalItemInfo.cs" />
+    <Compile Include="Sync\LocalItemQuery.cs" />
     <Compile Include="Sync\SyncCategory.cs" />
     <Compile Include="Sync\SyncDataRequest.cs" />
     <Compile Include="Sync\SyncDataResponse.cs" />
     <Compile Include="Sync\SyncDialogOptions.cs" />
     <Compile Include="Sync\SyncedItem.cs" />
-    <Compile Include="Sync\SyncHelper.cs" />
     <Compile Include="Sync\SyncJob.cs" />
     <Compile Include="Sync\SyncJobCreationResult.cs" />
     <Compile Include="Sync\SyncJobItem.cs" />
@@ -390,7 +397,8 @@
     <Compile Include="Sync\SyncJobStatus.cs" />
     <Compile Include="Sync\SyncOptions.cs" />
     <Compile Include="Sync\SyncParameter.cs" />
-    <Compile Include="Sync\SyncQuality.cs" />
+    <Compile Include="Sync\SyncProfileOption.cs" />
+    <Compile Include="Sync\SyncQualityOption.cs" />
     <Compile Include="Sync\SyncTarget.cs" />
     <Compile Include="System\LogFile.cs" />
     <Compile Include="System\PublicSystemInfo.cs" />
diff --git a/MediaBrowser.Model/MediaInfo/LiveMediaInfoResult.cs b/MediaBrowser.Model/MediaInfo/LiveMediaInfoResult.cs
index afd5c890f4..4a206ea202 100644
--- a/MediaBrowser.Model/MediaInfo/LiveMediaInfoResult.cs
+++ b/MediaBrowser.Model/MediaInfo/LiveMediaInfoResult.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Dto;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Model.MediaInfo
@@ -17,6 +18,12 @@ namespace MediaBrowser.Model.MediaInfo
         /// <value>The live stream identifier.</value>
         public string LiveStreamId { get; set; }
 
+        /// <summary>
+        /// Gets or sets the error code.
+        /// </summary>
+        /// <value>The error code.</value>
+        public PlaybackErrorCode? ErrorCode { get; set; }
+
         public LiveMediaInfoResult()
         {
             MediaSources = new List<MediaSourceInfo>();
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 1f54e48d11..56cfff7335 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -265,12 +265,7 @@ namespace MediaBrowser.Model.Net
                 return "application/ttml+xml";
             }
 
-            if (ext.Equals(".bif", StringComparison.OrdinalIgnoreCase))
-            {
-                return "application/octet-stream";
-            }
-
-            throw new ArgumentException("Argument not supported: " + path);
+            return "application/octet-stream";
         }
 
         public static string ToExtension(string mimeType)
diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs
index 7d80f31774..e57955c9e2 100644
--- a/MediaBrowser.Model/Notifications/NotificationOptions.cs
+++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs
@@ -64,6 +64,12 @@ namespace MediaBrowser.Model.Notifications
                     Type = NotificationType.PluginError.ToString(),
                     Enabled = true,
                     SendToUserMode = SendToUserType.Admins
+                },
+                new NotificationOption
+                {
+                    Type = NotificationType.UserLockedOut.ToString(),
+                    Enabled = true,
+                    SendToUserMode = SendToUserType.Admins
                 }
             };
         }
diff --git a/MediaBrowser.Model/Notifications/NotificationType.cs b/MediaBrowser.Model/Notifications/NotificationType.cs
index 269e27a4fc..f5e3624f00 100644
--- a/MediaBrowser.Model/Notifications/NotificationType.cs
+++ b/MediaBrowser.Model/Notifications/NotificationType.cs
@@ -19,6 +19,7 @@ namespace MediaBrowser.Model.Notifications
         NewLibraryContentMultiple,
         ServerRestartRequired,
         TaskFailed,
-        CameraImageUploaded
+        CameraImageUploaded,
+        UserLockedOut
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs
index 0f929fa9bb..0cdf5ca7ab 100644
--- a/MediaBrowser.Model/Querying/ItemQuery.cs
+++ b/MediaBrowser.Model/Querying/ItemQuery.cs
@@ -39,11 +39,11 @@ namespace MediaBrowser.Model.Querying
         public string[] SortBy { get; set; }
 
         /// <summary>
-        /// Filter by artists
+        /// Gets or sets the artist ids.
         /// </summary>
-        /// <value>The artists.</value>
-        public string[] Artists { get; set; }
-
+        /// <value>The artist ids.</value>
+        public string[] ArtistIds { get; set; }
+        
         /// <summary>
         /// The sort order to return results with
         /// </summary>
@@ -93,16 +93,10 @@ namespace MediaBrowser.Model.Querying
         public string[] Genres { get; set; }
 
         /// <summary>
-        /// Limit results to items containing specific genres
-        /// </summary>
-        /// <value>The genres.</value>
-        public string[] AllGenres { get; set; }
-
-        /// <summary>
-        /// Limit results to items containing specific studios
+        /// Gets or sets the studio ids.
         /// </summary>
-        /// <value>The studios.</value>
-        public string[] Studios { get; set; }
+        /// <value>The studio ids.</value>
+        public string[] StudioIds { get; set; }
 
         /// <summary>
         /// Gets or sets the exclude item types.
@@ -126,7 +120,7 @@ namespace MediaBrowser.Model.Querying
         /// Limit results to items containing a specific person
         /// </summary>
         /// <value>The person.</value>
-        public string Person { get; set; }
+        public string[] PersonIds { get; set; }
 
         /// <summary>
         /// If the Person filter is used, this can also be used to restrict to a specific person type
@@ -306,13 +300,14 @@ namespace MediaBrowser.Model.Querying
             VideoTypes = new VideoType[] { };
 
             Genres = new string[] { };
-            Studios = new string[] { };
+            StudioIds = new string[] { };
             IncludeItemTypes = new string[] { };
             ExcludeItemTypes = new string[] { };
             Years = new int[] { };
             PersonTypes = new string[] { };
             Ids = new string[] { };
-            Artists = new string[] { };
+            ArtistIds = new string[] { };
+            PersonIds = new string[] { };
 
             ImageTypes = new ImageType[] { };
             AirDays = new DayOfWeek[] { };
diff --git a/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs b/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs
new file mode 100644
index 0000000000..91417a4a77
--- /dev/null
+++ b/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs
@@ -0,0 +1,39 @@
+
+namespace MediaBrowser.Model.Querying
+{
+    public class MovieRecommendationQuery
+    {
+        /// <summary>
+        /// Gets or sets the user identifier.
+        /// </summary>
+        /// <value>The user identifier.</value>
+        public string UserId { get; set; }
+        /// <summary>
+        /// Gets or sets the parent identifier.
+        /// </summary>
+        /// <value>The parent identifier.</value>
+        public string ParentId { get; set; }
+        /// <summary>
+        /// Gets or sets the item limit.
+        /// </summary>
+        /// <value>The item limit.</value>
+        public int ItemLimit { get; set; }
+        /// <summary>
+        /// Gets or sets the category limit.
+        /// </summary>
+        /// <value>The category limit.</value>
+        public int CategoryLimit { get; set; }
+        /// <summary>
+        /// Gets or sets the fields.
+        /// </summary>
+        /// <value>The fields.</value>
+        public ItemFields[] Fields { get; set; }
+
+        public MovieRecommendationQuery()
+        {
+            ItemLimit = 10;
+            CategoryLimit = 6;
+            Fields = new ItemFields[] { };
+        }
+    }
+}
diff --git a/MediaBrowser.Model/Querying/SimilarItemsByNameQuery.cs b/MediaBrowser.Model/Querying/SimilarItemsByNameQuery.cs
deleted file mode 100644
index 7d0d4da317..0000000000
--- a/MediaBrowser.Model/Querying/SimilarItemsByNameQuery.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace MediaBrowser.Model.Querying
-{
-    public class SimilarItemsByNameQuery
-    {
-        /// <summary>
-        /// The user to localize search results for
-        /// </summary>
-        /// <value>The user id.</value>
-        public string UserId { get; set; }
-
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name { get; set; }
-
-        /// <summary>
-        /// The maximum number of items to return
-        /// </summary>
-        /// <value>The limit.</value>
-        public int? Limit { get; set; }
-
-        /// <summary>
-        /// Fields to return within the items, in addition to basic information
-        /// </summary>
-        /// <value>The fields.</value>
-        public ItemFields[] Fields { get; set; }
-    }
-}
\ No newline at end of file
diff --git a/MediaBrowser.Model/Registration/RegistrationInfo.cs b/MediaBrowser.Model/Registration/RegistrationInfo.cs
new file mode 100644
index 0000000000..4e97989cff
--- /dev/null
+++ b/MediaBrowser.Model/Registration/RegistrationInfo.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace MediaBrowser.Model.Registration
+{
+    public class RegistrationInfo
+    {
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+        /// <summary>
+        /// Gets or sets the expiration date.
+        /// </summary>
+        /// <value>The expiration date.</value>
+        public DateTime ExpirationDate { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is trial.
+        /// </summary>
+        /// <value><c>true</c> if this instance is trial; otherwise, <c>false</c>.</value>
+        public bool IsTrial { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is registered.
+        /// </summary>
+        /// <value><c>true</c> if this instance is registered; otherwise, <c>false</c>.</value>
+        public bool IsRegistered { get; set; }
+    }
+}
diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs
index 6ca4507c02..9361a60ea4 100644
--- a/MediaBrowser.Model/Session/ClientCapabilities.cs
+++ b/MediaBrowser.Model/Session/ClientCapabilities.cs
@@ -20,11 +20,6 @@ namespace MediaBrowser.Model.Session
 
         public DeviceProfile DeviceProfile { get; set; }
 
-        /// <summary>
-        /// Usage should be migrated to SupportsPersistentIdentifier. Keeping this to preserve data.
-        /// </summary>
-        public bool? SupportsUniqueIdentifier { get; set; }
-        
         public ClientCapabilities()
         {
             PlayableMediaTypes = new List<string>();
diff --git a/MediaBrowser.Model/Sync/LocalItemInfo.cs b/MediaBrowser.Model/Sync/LocalItemInfo.cs
new file mode 100644
index 0000000000..f52873b2f7
--- /dev/null
+++ b/MediaBrowser.Model/Sync/LocalItemInfo.cs
@@ -0,0 +1,11 @@
+
+namespace MediaBrowser.Model.Sync
+{
+    public class LocalItemInfo
+    {
+        public string ServerId { get; set; }
+        public string Id { get; set; }
+        public string Name { get; set; }
+        public string PrimaryImageTag { get; set; }
+    }
+}
diff --git a/MediaBrowser.Model/Sync/LocalItemQuery.cs b/MediaBrowser.Model/Sync/LocalItemQuery.cs
new file mode 100644
index 0000000000..0993929083
--- /dev/null
+++ b/MediaBrowser.Model/Sync/LocalItemQuery.cs
@@ -0,0 +1,19 @@
+
+namespace MediaBrowser.Model.Sync
+{
+    public class LocalItemQuery
+    {
+        public string ServerId { get; set; }
+        public string AlbumArtist { get; set; }
+        public string AlbumId { get; set; }
+        public string SeriesId { get; set; }
+        public string Type { get; set; }
+        public string MediaType { get; set; }
+        public string[] ExcludeTypes { get; set; }
+
+        public LocalItemQuery()
+        {
+            ExcludeTypes = new string[] { };
+        }
+    }
+}
diff --git a/MediaBrowser.Model/Sync/SyncDialogOptions.cs b/MediaBrowser.Model/Sync/SyncDialogOptions.cs
index cf8b0130b3..a987a6cd69 100644
--- a/MediaBrowser.Model/Sync/SyncDialogOptions.cs
+++ b/MediaBrowser.Model/Sync/SyncDialogOptions.cs
@@ -18,19 +18,19 @@ namespace MediaBrowser.Model.Sync
         /// Gets or sets the quality options.
         /// </summary>
         /// <value>The quality options.</value>
-        public List<SyncQuality> QualityOptions { get; set; }
-        
+        public List<SyncQualityOption> QualityOptions { get; set; }
+        /// <summary>
+        /// Gets or sets the profile options.
+        /// </summary>
+        /// <value>The profile options.</value>
+        public List<SyncProfileOption> ProfileOptions { get; set; }
+     
         public SyncDialogOptions()
         {
             Targets = new List<SyncTarget>();
             Options = new List<SyncJobOption>();
-            QualityOptions = new List<SyncQuality>
-            {
-                SyncQuality.Original,
-                SyncQuality.High,
-                SyncQuality.Medium,
-                SyncQuality.Low
-            };
+            QualityOptions = new List<SyncQualityOption>();
+            ProfileOptions = new List<SyncProfileOption>();
         }
     }
 }
diff --git a/MediaBrowser.Model/Sync/SyncJob.cs b/MediaBrowser.Model/Sync/SyncJob.cs
index 93e73d22e3..6709426b81 100644
--- a/MediaBrowser.Model/Sync/SyncJob.cs
+++ b/MediaBrowser.Model/Sync/SyncJob.cs
@@ -24,7 +24,17 @@ namespace MediaBrowser.Model.Sync
         /// Gets or sets the quality.
         /// </summary>
         /// <value>The quality.</value>
-        public SyncQuality Quality { get; set; }
+        public string Quality { get; set; }
+        /// <summary>
+        /// Gets or sets the bitrate.
+        /// </summary>
+        /// <value>The bitrate.</value>
+        public int? Bitrate { get; set; }
+        /// <summary>
+        /// Gets or sets the profile.
+        /// </summary>
+        /// <value>The profile.</value>
+        public string Profile { get; set; }
         /// <summary>
         /// Gets or sets the category.
         /// </summary>
@@ -98,7 +108,6 @@ namespace MediaBrowser.Model.Sync
         public SyncJob()
         {
             RequestedItemIds = new List<string>();
-            Quality = SyncQuality.High;
         }
     }
 }
diff --git a/MediaBrowser.Model/Sync/SyncJobItemQuery.cs b/MediaBrowser.Model/Sync/SyncJobItemQuery.cs
index d211382049..74d3ac096a 100644
--- a/MediaBrowser.Model/Sync/SyncJobItemQuery.cs
+++ b/MediaBrowser.Model/Sync/SyncJobItemQuery.cs
@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-
+
 namespace MediaBrowser.Model.Sync
 {
     public class SyncJobItemQuery
@@ -20,6 +19,11 @@ namespace MediaBrowser.Model.Sync
         /// <value>The job identifier.</value>
         public string JobId { get; set; }
         /// <summary>
+        /// Gets or sets the item identifier.
+        /// </summary>
+        /// <value>The item identifier.</value>
+        public string ItemId { get; set; }
+        /// <summary>
         /// Gets or sets the target identifier.
         /// </summary>
         /// <value>The target identifier.</value>
@@ -28,7 +32,7 @@ namespace MediaBrowser.Model.Sync
         /// Gets or sets the status.
         /// </summary>
         /// <value>The status.</value>
-        public List<SyncJobItemStatus> Statuses { get; set; }
+        public SyncJobItemStatus[] Statuses { get; set; }
         /// <summary>
         /// Gets or sets a value indicating whether [add metadata].
         /// </summary>
@@ -37,7 +41,7 @@ namespace MediaBrowser.Model.Sync
 
         public SyncJobItemQuery()
         {
-            Statuses = new List<SyncJobItemStatus>();
+            Statuses = new SyncJobItemStatus[] {};
         }
     }
 }
diff --git a/MediaBrowser.Model/Sync/SyncJobQuery.cs b/MediaBrowser.Model/Sync/SyncJobQuery.cs
index 233dc7878a..e86ec929f2 100644
--- a/MediaBrowser.Model/Sync/SyncJobQuery.cs
+++ b/MediaBrowser.Model/Sync/SyncJobQuery.cs
@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-
+
 namespace MediaBrowser.Model.Sync
 {
     public class SyncJobQuery
@@ -28,7 +27,7 @@ namespace MediaBrowser.Model.Sync
         /// Gets or sets the status.
         /// </summary>
         /// <value>The status.</value>
-        public List<SyncJobStatus> Statuses { get; set; }
+        public SyncJobStatus[] Statuses { get; set; }
         /// <summary>
         /// Gets or sets a value indicating whether [synchronize new content].
         /// </summary>
@@ -37,7 +36,7 @@ namespace MediaBrowser.Model.Sync
 
         public SyncJobQuery()
         {
-            Statuses = new List<SyncJobStatus>();
+            Statuses = new SyncJobStatus[] { };
         }
     }
 }
diff --git a/MediaBrowser.Model/Sync/SyncJobRequest.cs b/MediaBrowser.Model/Sync/SyncJobRequest.cs
index 7d3016d0ef..a96c86ed9c 100644
--- a/MediaBrowser.Model/Sync/SyncJobRequest.cs
+++ b/MediaBrowser.Model/Sync/SyncJobRequest.cs
@@ -28,7 +28,12 @@ namespace MediaBrowser.Model.Sync
         /// Gets or sets the quality.
         /// </summary>
         /// <value>The quality.</value>
-        public SyncQuality Quality { get; set; }
+        public string Quality { get; set; }
+        /// <summary>
+        /// Gets or sets the profile.
+        /// </summary>
+        /// <value>The profile.</value>
+        public string Profile { get; set; }
         /// <summary>
         /// Gets or sets the name.
         /// </summary>
@@ -54,6 +59,11 @@ namespace MediaBrowser.Model.Sync
         /// </summary>
         /// <value>The limit.</value>
         public int? ItemLimit { get; set; }
+        /// <summary>
+        /// Gets or sets the bitrate.
+        /// </summary>
+        /// <value>The bitrate.</value>
+        public int? Bitrate { get; set; }
 
         public SyncJobRequest()
         {
diff --git a/MediaBrowser.Model/Sync/SyncParameter.cs b/MediaBrowser.Model/Sync/SyncParameter.cs
index def4ab3e3f..bce2a4f307 100644
--- a/MediaBrowser.Model/Sync/SyncParameter.cs
+++ b/MediaBrowser.Model/Sync/SyncParameter.cs
@@ -7,6 +7,7 @@ namespace MediaBrowser.Model.Sync
         Quality = 1,
         UnwatchedOnly = 2,
         SyncNewContent = 3,
-        ItemLimit = 4
+        ItemLimit = 4,
+        Profile = 5
     }
 }
diff --git a/MediaBrowser.Model/Sync/SyncProfileOption.cs b/MediaBrowser.Model/Sync/SyncProfileOption.cs
new file mode 100644
index 0000000000..605af6b25c
--- /dev/null
+++ b/MediaBrowser.Model/Sync/SyncProfileOption.cs
@@ -0,0 +1,37 @@
+
+namespace MediaBrowser.Model.Sync
+{
+    public class SyncProfileOption
+    {
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+        /// <summary>
+        /// Gets or sets the description.
+        /// </summary>
+        /// <value>The description.</value>
+        public string Description { get; set; }
+        /// <summary>
+        /// Gets or sets the identifier.
+        /// </summary>
+        /// <value>The identifier.</value>
+        public string Id { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is default.
+        /// </summary>
+        /// <value><c>true</c> if this instance is default; otherwise, <c>false</c>.</value>
+        public bool IsDefault { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether [enable quality options].
+        /// </summary>
+        /// <value><c>true</c> if [enable quality options]; otherwise, <c>false</c>.</value>
+        public bool EnableQualityOptions { get; set; }
+
+        public SyncProfileOption()
+        {
+            EnableQualityOptions = true;
+        }
+    }
+}
diff --git a/MediaBrowser.Model/Sync/SyncQuality.cs b/MediaBrowser.Model/Sync/SyncQuality.cs
deleted file mode 100644
index 27ee756a32..0000000000
--- a/MediaBrowser.Model/Sync/SyncQuality.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-
-namespace MediaBrowser.Model.Sync
-{
-    public enum SyncQuality
-    {
-        /// <summary>
-        /// The good
-        /// </summary>
-        Low = 0,
-
-        /// <summary>
-        /// The better
-        /// </summary>
-        Medium = 1,
-
-        /// <summary>
-        /// The best
-        /// </summary>
-        High = 2,
-        /// <summary>
-        /// The original
-        /// </summary>
-        Original = 3
-    }
-}
diff --git a/MediaBrowser.Model/Sync/SyncQualityOption.cs b/MediaBrowser.Model/Sync/SyncQualityOption.cs
new file mode 100644
index 0000000000..597b987270
--- /dev/null
+++ b/MediaBrowser.Model/Sync/SyncQualityOption.cs
@@ -0,0 +1,27 @@
+
+namespace MediaBrowser.Model.Sync
+{
+    public class SyncQualityOption
+    {
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+        /// <summary>
+        /// Gets or sets the description.
+        /// </summary>
+        /// <value>The description.</value>
+        public string Description { get; set; }
+        /// <summary>
+        /// Gets or sets the identifier.
+        /// </summary>
+        /// <value>The identifier.</value>
+        public string Id { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is default.
+        /// </summary>
+        /// <value><c>true</c> if this instance is default; otherwise, <c>false</c>.</value>
+        public bool IsDefault { get; set; }
+    }
+}
diff --git a/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs b/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs
index e03d859841..aacd56e655 100644
--- a/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs
+++ b/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs
@@ -36,5 +36,11 @@ namespace MediaBrowser.Model.Tasks
         /// </summary>
         /// <value>The day of week.</value>
         public DayOfWeek? DayOfWeek { get; set; }
+
+        /// <summary>
+        /// Gets or sets the maximum runtime ms.
+        /// </summary>
+        /// <value>The maximum runtime ms.</value>
+        public int? MaxRuntimeMs { get; set; }
     }
 }
diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs
index 410cdc51f3..7efc2cf6f6 100644
--- a/MediaBrowser.Model/Users/UserPolicy.cs
+++ b/MediaBrowser.Model/Users/UserPolicy.cs
@@ -59,6 +59,8 @@ namespace MediaBrowser.Model.Users
         public string[] EnabledFolders { get; set; }
         public bool EnableAllFolders { get; set; }
 
+        public int InvalidLoginAttemptCount { get; set; }
+        
         public UserPolicy()
         {
             EnableLiveTvManagement = true;
diff --git a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs b/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
index 8ddbbba7dc..3550ee6885 100644
--- a/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
+++ b/MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Providers.FolderImages
 {
-    public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor
+    public class DefaultImageProvider : IRemoteImageProvider, IHasItemChangeMonitor, IHasOrder
     {
         private readonly IHttpClient _httpClient;
 
@@ -36,70 +36,81 @@ namespace MediaBrowser.Providers.FolderImages
 
             if (view != null)
             {
-                return GetImages(view.ViewType, cancellationToken);
+                return GetImages(view.ViewType, view.ParentId != Guid.Empty, cancellationToken);
             }
 
             var folder = (ICollectionFolder)item;
-            return GetImages(folder.CollectionType, cancellationToken);
+            return GetImages(folder.CollectionType, false, cancellationToken);
         }
 
-        private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, CancellationToken cancellationToken)
+        private Task<IEnumerable<RemoteImageInfo>> GetImages(string viewType, bool isSubView, CancellationToken cancellationToken)
         {
-            var url = GetImageUrl(viewType);
+            var url = GetImageUrl(viewType, isSubView);
+            var list = new List<RemoteImageInfo>();
 
-            return Task.FromResult<IEnumerable<RemoteImageInfo>>(new List<RemoteImageInfo>
+            if (!string.IsNullOrWhiteSpace(url))
             {
-                 new RemoteImageInfo
-                 {
-                      ProviderName = Name,
-                      Url = url,
-                      Type = ImageType.Primary
-                 },
-
-                 new RemoteImageInfo
-                 {
-                      ProviderName = Name,
-                      Url = url,
-                      Type = ImageType.Thumb
-                 }
-            });
+                list.AddRange(new List<RemoteImageInfo>
+                {
+                    new RemoteImageInfo
+                    {
+                        ProviderName = Name,
+                        Url = url,
+                        Type = ImageType.Primary
+                    },
+
+                    new RemoteImageInfo
+                    {
+                        ProviderName = Name,
+                        Url = url,
+                        Type = ImageType.Thumb
+                    }
+                });
+            }
+
+            return Task.FromResult<IEnumerable<RemoteImageInfo>>(list);
         }
 
-        private string GetImageUrl(string viewType)
+        private string GetImageUrl(string viewType, bool isSubView)
         {
             const string urlPrefix = "https://raw.githubusercontent.com/MediaBrowser/MediaBrowser.Resources/master/images/folders/";
 
             if (string.Equals(viewType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "books.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "games.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.Music, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "music.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "photos.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "tv.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.Channels, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "channels.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "livetv.png";
+                return null;
             }
             if (string.Equals(viewType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
             {
-                return urlPrefix + "movies.png";
+                return null;
+            }
+
+            if (isSubView)
+            {
+                return null;
             }
 
             return urlPrefix + "generic.png";
@@ -112,14 +123,7 @@ namespace MediaBrowser.Providers.FolderImages
 
         public bool Supports(IHasImages item)
         {
-            var view = item as UserView;
-
-            if (view != null)
-            {
-                return !view.UserId.HasValue;
-            }
-            
-            return item is ICollectionFolder;
+            return item is ICollectionFolder || item is UserView;
         }
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
@@ -136,5 +140,14 @@ namespace MediaBrowser.Providers.FolderImages
         {
             return GetSupportedImages(item).Any(i => !item.HasImage(i));
         }
+
+        public int Order
+        {
+            get
+            {
+                // Run after the dynamic image provider
+                return 1;
+            }
+        }
     }
 }
diff --git a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
index 5a7ae75947..f17389615f 100644
--- a/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
+++ b/MediaBrowser.Providers/LiveTv/ProgramMetadataService.cs
@@ -7,14 +7,16 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Providers.Manager;
 using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Providers.LiveTv
 {
-    public class ProgramMetadataService : MetadataService<LiveTvProgram, ItemLookupInfo>
+    public class ProgramMetadataService : MetadataService<LiveTvProgram, LiveTvProgramLookupInfo>
     {
-        public ProgramMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager) : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
+        public ProgramMetadataService(
+            IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager,
+            IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager)
+            : base(
+                serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
         {
         }
 
@@ -25,6 +27,7 @@ namespace MediaBrowser.Providers.LiveTv
         /// <param name="target">The target.</param>
         /// <param name="lockedFields">The locked fields.</param>
         /// <param name="replaceData">if set to <c>true</c> [replace data].</param>
+        /// <param name="mergeMetadataSettings"></param>
         protected override void MergeData(LiveTvProgram source, LiveTvProgram target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
         {
             ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index a8e16e4ae5..22178434fb 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -82,14 +82,6 @@ namespace MediaBrowser.Providers.Manager
             {
                 saveLocally = true;
             }
-            if (item is IItemByName)
-            {
-                var hasDualAccess = item as IHasDualAccess;
-                if (hasDualAccess == null || hasDualAccess.IsAccessedByName)
-                {
-                    saveLocally = true;
-                }
-            }
 
             if (type != ImageType.Primary && item is Episode)
             {
diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
index 66b0f92597..3c75aa20ad 100644
--- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs
+++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs
@@ -135,17 +135,17 @@ namespace MediaBrowser.Providers.Manager
                         {
                             if (!string.IsNullOrEmpty(response.Path))
                             {
-                                var mimeType = "image/" + Path.GetExtension(response.Path).TrimStart('.').ToLower();
+                                var mimeType = MimeTypes.GetMimeType(response.Path);
 
                                 var stream = _fileSystem.GetFileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, true);
 
-                                await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
+                                await _providerManager.SaveImage(item, stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
                             }
                             else
                             {
                                 var mimeType = "image/" + response.Format.ToString().ToLower();
 
-                                await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false);
+                                await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, response.InternalCacheKey, cancellationToken).ConfigureAwait(false);
                             }
 
                             downloadedImages.Add(imageType);
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index ab6cb89a62..ab95256364 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -87,7 +87,7 @@ namespace MediaBrowser.Providers.Manager
             return ProviderRepo.GetMetadataStatus(item.Id) ?? new MetadataStatus { ItemId = item.Id };
         }
 
-        public async Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
+        public async Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
         {
             var itemOfType = (TItemType)item;
             var config = ProviderManager.GetMetadataOptions(item);
@@ -163,7 +163,8 @@ namespace MediaBrowser.Providers.Manager
                 }
             }
 
-            updateType = updateType | (await BeforeSave(itemOfType, item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata, updateType).ConfigureAwait(false));
+            var beforeSaveResult = await BeforeSave(itemOfType, item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh, updateType).ConfigureAwait(false);
+            updateType = updateType | beforeSaveResult;
 
             // Save if changes were made, or it's never been saved before
             if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || item.DateLastSaved == default(DateTime) || refreshOptions.ReplaceAllMetadata)
@@ -184,6 +185,8 @@ namespace MediaBrowser.Providers.Manager
             }
 
             await AfterMetadataRefresh(itemOfType, refreshOptions, cancellationToken).ConfigureAwait(false);
+
+            return updateType;
         }
 
         private readonly Task _cachedTask = Task.FromResult(true);
@@ -397,7 +400,10 @@ namespace MediaBrowser.Providers.Manager
                         refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
 
                         // Only one local provider allowed per item
-                        hasLocalMetadata = true;
+                        if (IsFullLocalMetadata(localItem.Item))
+                        {
+                            hasLocalMetadata = true;
+                        }
                         successfulProviderCount++;
                         break;
                     }
@@ -473,6 +479,11 @@ namespace MediaBrowser.Providers.Manager
             return refreshResult;
         }
 
+        protected virtual bool IsFullLocalMetadata(TItemType item)
+        {
+            return true;
+        }
+
         private async Task ImportUserData(TItemType item, List<UserItemData> userDataList, CancellationToken cancellationToken)
         {
             var hasUserData = item as IHasUserData;
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index 823c34a756..c9ae47ad0b 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -26,7 +26,7 @@ namespace MediaBrowser.Providers.Manager
     /// <summary>
     /// Class ProviderManager
     /// </summary>
-    public class ProviderManager : IProviderManager
+    public class ProviderManager : IProviderManager, IDisposable
     {
         /// <summary>
         /// The _logger
@@ -63,6 +63,8 @@ namespace MediaBrowser.Providers.Manager
 
         private IExternalId[] _externalIds;
 
+        private readonly Func<ILibraryManager> _libraryManagerFactory;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
         /// </summary>
@@ -71,7 +73,7 @@ namespace MediaBrowser.Providers.Manager
         /// <param name="libraryMonitor">The directory watchers.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="fileSystem">The file system.</param>
-        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths)
+        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IServerApplicationPaths appPaths, Func<ILibraryManager> libraryManagerFactory)
         {
             _logger = logManager.GetLogger("ProviderManager");
             _httpClient = httpClient;
@@ -79,6 +81,7 @@ namespace MediaBrowser.Providers.Manager
             _libraryMonitor = libraryMonitor;
             _fileSystem = fileSystem;
             _appPaths = appPaths;
+            _libraryManagerFactory = libraryManagerFactory;
         }
 
         /// <summary>
@@ -108,7 +111,7 @@ namespace MediaBrowser.Providers.Manager
             _externalIds = externalIds.OrderBy(i => i.Name).ToArray();
         }
 
-        public Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        public Task<ItemUpdateType> RefreshSingleItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
             var service = _metadataServices.FirstOrDefault(i => i.CanRefresh(item));
 
@@ -118,7 +121,7 @@ namespace MediaBrowser.Providers.Manager
             }
 
             _logger.Error("Unable to find a metadata service for item of type " + item.GetType().Name);
-            return Task.FromResult(true);
+            return Task.FromResult(ItemUpdateType.None);
         }
 
         public async Task SaveImage(IHasImages item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken)
@@ -309,7 +312,7 @@ namespace MediaBrowser.Providers.Manager
 
                 if (provider is IRemoteMetadataProvider)
                 {
-                    if (!ConfigurationManager.Configuration.EnableInternetProviders)
+                    if (!item.IsInternetMetadataEnabled())
                     {
                         return false;
                     }
@@ -357,7 +360,7 @@ namespace MediaBrowser.Providers.Manager
 
                     if (provider is IRemoteImageProvider)
                     {
-                        if (!ConfigurationManager.Configuration.EnableInternetProviders)
+                        if (!item.IsInternetMetadataEnabled())
                         {
                             return false;
                         }
@@ -512,7 +515,7 @@ namespace MediaBrowser.Providers.Manager
                 Type = MetadataPluginType.LocalMetadataProvider
             }));
 
-            if (ConfigurationManager.Configuration.EnableInternetProviders)
+            if (item.IsInternetMetadataEnabled())
             {
                 // Fetchers
                 list.AddRange(providers.Where(i => (i is IRemoteMetadataProvider)).Select(i => new MetadataPlugin
@@ -544,7 +547,7 @@ namespace MediaBrowser.Providers.Manager
                 Type = MetadataPluginType.LocalImageProvider
             }));
 
-            var enableInternet = ConfigurationManager.Configuration.EnableInternetProviders;
+            var enableInternet = item.IsInternetMetadataEnabled();
 
             // Fetchers
             list.AddRange(imageProviders.Where(i => i is IDynamicImageProvider || (enableInternet && i is IRemoteImageProvider)).Select(i => new MetadataPlugin
@@ -841,5 +844,157 @@ namespace MediaBrowser.Providers.Manager
 
                 });
         }
+
+        private readonly ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>> _refreshQueue =
+            new ConcurrentQueue<Tuple<Guid, MetadataRefreshOptions>>();
+
+        private readonly object _refreshTimerLock = new object();
+        private Timer _refreshTimer;
+
+        public void QueueRefresh(Guid id, MetadataRefreshOptions options)
+        {
+            if (_disposed)
+            {
+                return;
+            }
+
+            _refreshQueue.Enqueue(new Tuple<Guid, MetadataRefreshOptions>(id, options));
+            StartRefreshTimer();
+        }
+
+        private void StartRefreshTimer()
+        {
+            lock (_refreshTimerLock)
+            {
+                if (_refreshTimer == null)
+                {
+                    _refreshTimer = new Timer(RefreshTimerCallback, null, 100, Timeout.Infinite);
+                }
+            }
+        }
+
+        private void StopRefreshTimer()
+        {
+            lock (_refreshTimerLock)
+            {
+                if (_refreshTimer != null)
+                {
+                    _refreshTimer.Dispose();
+                    _refreshTimer = null;
+                }
+            }
+        }
+
+        private async void RefreshTimerCallback(object state)
+        {
+            Tuple<Guid, MetadataRefreshOptions> refreshItem;
+            var libraryManager = _libraryManagerFactory();
+
+            while (_refreshQueue.TryDequeue(out refreshItem))
+            {
+                if (_disposed)
+                {
+                    return;
+                }
+
+                var item = libraryManager.GetItemById(refreshItem.Item1);
+                if (item != null)
+                {
+                    try
+                    {
+                        var artist = item as MusicArtist;
+                        var task = artist == null
+                            ? RefreshItem(item, refreshItem.Item2, CancellationToken.None)
+                            : RefreshArtist(artist, refreshItem.Item2);
+
+                        await task.ConfigureAwait(false);
+                    }
+                    catch (Exception ex)
+                    {
+                        _logger.ErrorException("Error refreshing item", ex);
+                    }
+                }
+            }
+
+            StopRefreshTimer();
+        }
+
+        private async Task RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+
+            if (item.IsFolder)
+            {
+                // Collection folders don't validate their children so we'll have to simulate that here
+                var collectionFolder = item as CollectionFolder;
+
+                if (collectionFolder != null)
+                {
+                    await RefreshCollectionFolderChildren(options, collectionFolder).ConfigureAwait(false);
+                }
+                else
+                {
+                    var folder = (Folder)item;
+
+                    await folder.ValidateChildren(new Progress<double>(), cancellationToken, options).ConfigureAwait(false);
+                }
+            }
+        }
+
+        private async Task RefreshCollectionFolderChildren(MetadataRefreshOptions options, CollectionFolder collectionFolder)
+        {
+            foreach (var child in collectionFolder.Children.ToList())
+            {
+                await child.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+
+                if (child.IsFolder)
+                {
+                    var folder = (Folder)child;
+
+                    await folder.ValidateChildren(new Progress<double>(), CancellationToken.None).ConfigureAwait(false);
+                }
+            }
+        }
+
+        private async Task RefreshArtist(MusicArtist item, MetadataRefreshOptions options)
+        {
+            var cancellationToken = CancellationToken.None;
+
+            var albums = _libraryManagerFactory().RootFolder
+                                        .GetRecursiveChildren()
+                                        .OfType<MusicAlbum>()
+                                        .Where(i => i.HasAnyArtist(item.Name))
+                                        .ToList();
+
+            var musicArtists = albums
+                .Select(i => i.Parent)
+                .OfType<MusicArtist>()
+                .ToList();
+
+            var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, options, true));
+
+            await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false);
+
+            try
+            {
+                await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error refreshing library", ex);
+            }
+        }
+
+        public Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options,
+            CancellationToken cancellationToken)
+        {
+            return RefreshItem((BaseItem)item, options, cancellationToken);
+        }
+
+        private bool _disposed;
+        public void Dispose()
+        {
+            _disposed = true;
+        }
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Providers/Manager/ProviderUtils.cs b/MediaBrowser.Providers/Manager/ProviderUtils.cs
index 155cd208f3..aa92cc2802 100644
--- a/MediaBrowser.Providers/Manager/ProviderUtils.cs
+++ b/MediaBrowser.Providers/Manager/ProviderUtils.cs
@@ -252,7 +252,7 @@ namespace MediaBrowser.Providers.Manager
 
             if (sourceHasAlbumArtist != null && targetHasAlbumArtist != null)
             {
-                if (replaceData || targetHasAlbumArtist.AlbumArtists.Count > 0)
+                if (replaceData || targetHasAlbumArtist.AlbumArtists.Count == 0)
                 {
                     targetHasAlbumArtist.AlbumArtists = sourceHasAlbumArtist.AlbumArtists;
                 }
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 2df8f8e3c5..3b5103f209 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -108,6 +108,7 @@
     <Compile Include="MediaInfo\SubtitleDownloader.cs" />
     <Compile Include="MediaInfo\SubtitleResolver.cs" />
     <Compile Include="MediaInfo\SubtitleScheduledTask.cs" />
+    <Compile Include="Movies\LiveTvMovieDbProvider.cs" />
     <Compile Include="Movies\MovieDbTrailerProvider.cs" />
     <Compile Include="Movies\MovieExternalIds.cs" />
     <Compile Include="Movies\GenericMovieDbInfo.cs" />
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
index 39f138c5bc..ea191dd08f 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs
@@ -210,7 +210,15 @@ namespace MediaBrowser.Providers.MediaInfo
                 }
             }
 
-            var albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "albumartist") ?? FFProbeHelpers.GetDictionaryValue(tags, "album artist") ?? FFProbeHelpers.GetDictionaryValue(tags, "album_artist");
+            var albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "albumartist");
+            if (string.IsNullOrWhiteSpace(albumArtist))
+            {
+                albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album artist");
+            }
+            if (string.IsNullOrWhiteSpace(albumArtist))
+            {
+                albumArtist = FFProbeHelpers.GetDictionaryValue(tags, "album_artist");
+            }
 
             if (string.IsNullOrWhiteSpace(albumArtist))
             {
@@ -277,8 +285,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
             return value.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)
                 .Select(i => i.Trim())
-                .Where(i => !string.IsNullOrWhiteSpace(i))
-                .FirstOrDefault();
+                .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
         }
 
         private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
@@ -380,7 +387,7 @@ namespace MediaBrowser.Providers.MediaInfo
             if (!string.IsNullOrEmpty(val))
             {
                 // Sometimes the artist name is listed here, account for that
-                var studios = Split(val, true).Where(i => !audio.HasArtist(i));
+                var studios = Split(val, true).Where(i => !audio.HasAnyArtist(i));
 
                 foreach (var studio in studios)
                 {
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index 90afba0b50..a6d3c0271d 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -35,7 +35,8 @@ namespace MediaBrowser.Providers.MediaInfo
         ICustomMetadataProvider<Audio>,
         IHasItemChangeMonitor,
         IHasOrder,
-        IForcedProvider
+        IForcedProvider,
+        IPreRefreshProvider
     {
         private readonly ILogger _logger;
         private readonly IIsoManager _isoManager;
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 5ec773532d..ca11f858af 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -419,6 +419,8 @@ namespace MediaBrowser.Providers.MediaInfo
             return _blurayExaminer.GetDiscInfo(path);
         }
 
+        public const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
+        
         private void FetchWtvInfo(Video video, InternalMediaInfoResult data)
         {
             if (data.format == null || data.format.tags == null)
@@ -426,78 +428,122 @@ namespace MediaBrowser.Providers.MediaInfo
                 return;
             }
 
-            if (video.Genres.Count == 0)
+            if (!video.LockedFields.Contains(MetadataFields.Genres))
             {
-                if (!video.LockedFields.Contains(MetadataFields.Genres))
-                {
-                    var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre");
+                var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre");
 
-                    if (!string.IsNullOrEmpty(genres))
-                    {
-                        video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
-                            .Where(i => !string.IsNullOrWhiteSpace(i))
-                            .Select(i => i.Trim())
-                            .ToList();
-                    }
+                if (!string.IsNullOrWhiteSpace(genres))
+                {
+                    //genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "genre");
                 }
-            }
 
-            if (string.IsNullOrEmpty(video.Overview))
-            {
-                if (!video.LockedFields.Contains(MetadataFields.Overview))
+                if (!string.IsNullOrWhiteSpace(genres))
                 {
-                    var overview = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");
-
-                    if (!string.IsNullOrWhiteSpace(overview))
-                    {
-                        video.Overview = overview;
-                    }
+                    video.Genres = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries)
+                        .Where(i => !string.IsNullOrWhiteSpace(i))
+                        .Select(i => i.Trim())
+                        .ToList();
                 }
             }
 
-            if (string.IsNullOrEmpty(video.OfficialRating))
+            if (!video.LockedFields.Contains(MetadataFields.OfficialRating))
             {
                 var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating");
 
                 if (!string.IsNullOrWhiteSpace(officialRating))
                 {
-                    if (!video.LockedFields.Contains(MetadataFields.OfficialRating))
-                    {
-                        video.OfficialRating = officialRating;
-                    }
+                    video.OfficialRating = officialRating;
                 }
             }
 
-            if (video.People.Count == 0)
+            if (!video.LockedFields.Contains(MetadataFields.Cast))
             {
-                if (!video.LockedFields.Contains(MetadataFields.Cast))
+                var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");
+
+                if (!string.IsNullOrEmpty(people))
                 {
-                    var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits");
+                    video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
+                        .Where(i => !string.IsNullOrWhiteSpace(i))
+                        .Select(i => new PersonInfo { Name = i.Trim(), Type = PersonType.Actor })
+                        .ToList();
+                }
+            }
 
-                    if (!string.IsNullOrEmpty(people))
-                    {
-                        video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries)
-                            .Where(i => !string.IsNullOrWhiteSpace(i))
-                            .Select(i => new PersonInfo { Name = i.Trim(), Type = PersonType.Actor })
-                            .ToList();
-                    }
+            var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
+            if (!string.IsNullOrWhiteSpace(year))
+            {
+                int val;
+
+                if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
+                {
+                    video.ProductionYear = val;
                 }
             }
 
-            if (!video.ProductionYear.HasValue)
+            var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime");
+            if (!string.IsNullOrWhiteSpace(premiereDateString))
             {
-                var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime");
+                DateTime val;
 
-                if (!string.IsNullOrWhiteSpace(year))
+                // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
+                // DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None)
+                if (DateTime.TryParse(year, null, DateTimeStyles.None, out val))
                 {
-                    int val;
+                    video.PremiereDate = val.ToUniversalTime();
+                }
+            }
+
+            var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription");
+            
+            var episode = video as Episode;
+            if (episode != null)
+            {
+                var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle");
 
-                    if (int.TryParse(year, NumberStyles.Integer, _usCulture, out val))
+                // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
+
+                // Sometimes for TV Shows the Subtitle field is empty and the subtitle description contains the subtitle, extract if possible. See ticket https://mcebuddy2x.codeplex.com/workitem/1910
+                // The format is -> EPISODE/TOTAL_EPISODES_IN_SEASON. SUBTITLE: DESCRIPTION
+                // OR -> COMMENT. SUBTITLE: DESCRIPTION
+                // e.g. -> 4/13. The Doctor's Wife: Science fiction drama. When he follows a Time Lord distress signal, the Doctor puts Amy, Rory and his beloved TARDIS in grave danger. Also in HD. [AD,S]
+                // e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S]
+                if (String.IsNullOrWhiteSpace(subTitle) && !String.IsNullOrWhiteSpace(description) && description.Substring(0, Math.Min(description.Length, MaxSubtitleDescriptionExtractionLength)).Contains(":")) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename
+                {
+                    string[] parts = description.Split(':');
+                    if (parts.Length > 0)
                     {
-                        video.ProductionYear = val;
+                        string subtitle = parts[0];
+                        try
+                        {
+                            if (subtitle.Contains("/")) // It contains a episode number and season number
+                            {
+                                string[] numbers = subtitle.Split(' ');
+                                episode.IndexNumber = int.Parse(numbers[0].Replace(".", "").Split('/')[0]);
+                                int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", "").Split('/')[1]);
+
+                                description = String.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it
+                            }
+                            else
+                                throw new Exception(); // Switch to default parsing
+                        }
+                        catch // Default parsing
+                        {
+                            if (subtitle.Contains(".")) // skip the comment, keep the subtitle
+                                description = String.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first
+                            else
+                                description = subtitle.Trim(); // Clean up whitespaces and save it
+                        }
                     }
                 }
             }
+
+            if (!video.LockedFields.Contains(MetadataFields.Overview))
+            {
+                if (!string.IsNullOrWhiteSpace(description))
+                {
+                    video.Overview = description;
+                }
+            }
         }
 
         private SubtitleOptions GetOptions()
diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
index 87b2290909..c23ed3786c 100644
--- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
+++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
@@ -17,7 +17,7 @@ using System.Threading.Tasks;
 namespace MediaBrowser.Providers.Movies
 {
     public class GenericMovieDbInfo<T>
-        where T : Video, new()
+        where T : BaseItem, new()
     {
         private readonly ILogger _logger;
         private readonly IJsonSerializer _jsonSerializer;
@@ -111,7 +111,13 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="movieData">The movie data.</param>
         private void ProcessMainInfo(T movie, string preferredCountryCode, MovieDbProvider.CompleteMovieData movieData)
         {
-            movie.Name = movieData.title ?? movieData.original_title ?? movieData.name ?? movie.Name;
+            movie.Name = movieData.GetTitle() ?? movie.Name;
+
+            var hasOriginalTitle = movie as IHasOriginalTitle;
+            if (hasOriginalTitle != null)
+            {
+                hasOriginalTitle.OriginalTitle = movieData.GetOriginalTitle();
+            }
 
             // Bug in Mono: WebUtility.HtmlDecode should return null if the string is null but in Mono it generate an System.ArgumentNullException.
             movie.Overview = movieData.overview != null ? WebUtility.HtmlDecode(movieData.overview) : null;
diff --git a/MediaBrowser.Providers/Movies/LiveTvMovieDbProvider.cs b/MediaBrowser.Providers/Movies/LiveTvMovieDbProvider.cs
new file mode 100644
index 0000000000..a2d35b5004
--- /dev/null
+++ b/MediaBrowser.Providers/Movies/LiveTvMovieDbProvider.cs
@@ -0,0 +1,38 @@
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Providers;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Providers.Movies
+{
+    public class LiveTvMovieDbProvider : IRemoteMetadataProvider<LiveTvProgram, LiveTvProgramLookupInfo>, IHasOrder
+    {
+        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(LiveTvProgramLookupInfo searchInfo, CancellationToken cancellationToken)
+        {
+            return MovieDbProvider.Current.GetMovieSearchResults(searchInfo, cancellationToken);
+        }
+
+        public Task<MetadataResult<LiveTvProgram>> GetMetadata(LiveTvProgramLookupInfo info, CancellationToken cancellationToken)
+        {
+            return MovieDbProvider.Current.GetItemMetadata<LiveTvProgram>(info, cancellationToken);
+        }
+
+        public string Name
+        {
+            get { return "LiveTvMovieDbProvider"; }
+        }
+
+        public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
+        {
+            return MovieDbProvider.Current.GetImageResponse(url, cancellationToken);
+        }
+
+        public int Order
+        {
+            get { return 1; }
+        }
+    }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
index f5d5a6fb1d..192addfb8f 100644
--- a/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbImageProvider.cs
@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Dto;
@@ -47,15 +48,20 @@ namespace MediaBrowser.Providers.Movies
                 return true;
             }
 
+            // Supports images for tv movies
+            var tvProgram = item as LiveTvProgram;
+            if (tvProgram != null && tvProgram.IsMovie)
+            {
+                return true;
+            }
+
             // Don't support local trailers
             return item is Movie || item is MusicVideo;
         }
 
         public IEnumerable<ImageType> GetSupportedImages(IHasImages item)
         {
-            var channelItem = item as ChannelVideoItem;
-
-            if (channelItem != null)
+            if (item is ChannelVideoItem || item is LiveTvProgram)
             {
                 // Too many channel items to allow backdrops here
                 return new List<ImageType>
diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
index ed15a2eeff..48b7140f86 100644
--- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs
@@ -77,7 +77,7 @@ namespace MediaBrowser.Providers.Movies
 
                 var remoteResult = new RemoteSearchResult
                 {
-                    Name = obj.title ?? obj.original_title ?? obj.name,
+                    Name = obj.GetTitle(),
                     SearchProviderName = Name,
                     ImageUrl = string.IsNullOrWhiteSpace(obj.poster_path) ? null : tmdbImageUrl + obj.poster_path
                 };
@@ -113,7 +113,7 @@ namespace MediaBrowser.Providers.Movies
         }
 
         public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken)
-            where T : Video, new()
+            where T : BaseItem, new()
         {
             var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer, _libraryManager);
 
@@ -560,6 +560,7 @@ namespace MediaBrowser.Providers.Movies
             public int id { get; set; }
             public string imdb_id { get; set; }
             public string original_title { get; set; }
+            public string original_name { get; set; }
             public string overview { get; set; }
             public double popularity { get; set; }
             public string poster_path { get; set; }
@@ -580,6 +581,16 @@ namespace MediaBrowser.Providers.Movies
             public Images images { get; set; }
             public Keywords keywords { get; set; }
             public Trailers trailers { get; set; }
+
+            public string GetOriginalTitle()
+            {
+                return original_name ?? original_title;
+            }
+
+            public string GetTitle()
+            {
+                return name ?? title ?? GetOriginalTitle();
+            }
         }
 
         public int Order
diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
index f1a4d7bba7..8a59d7a1b2 100644
--- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs
+++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs
@@ -147,7 +147,7 @@ namespace MediaBrowser.Providers.Movies
                         var remoteResult = new RemoteSearchResult
                         {
                             SearchProviderName = MovieDbProvider.Current.Name,
-                            Name = i.title ?? i.original_title ?? i.name,
+                            Name = i.title ?? i.name ?? i.original_title,
                             ImageUrl = string.IsNullOrWhiteSpace(i.poster_path) ? null : baseImageUrl + i.poster_path
                         };
                         
@@ -215,6 +215,11 @@ namespace MediaBrowser.Providers.Movies
             /// <value>The original_title.</value>
             public string original_title { get; set; }
             /// <summary>
+            /// Gets or sets the original_name.
+            /// </summary>
+            /// <value>The original_name.</value>
+            public string original_name { get; set; }
+            /// <summary>
             /// Gets or sets the release_date.
             /// </summary>
             /// <value>The release_date.</value>
diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
index af9970b699..172ae6814c 100644
--- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs
+++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs
@@ -33,5 +33,22 @@ namespace MediaBrowser.Providers.Movies
                 target.TmdbCollectionName = source.TmdbCollectionName;
             }
         }
+
+        protected override bool IsFullLocalMetadata(Movie item)
+        {
+            if (string.IsNullOrWhiteSpace(item.Name))
+            {
+                return false;
+            }
+            if (string.IsNullOrWhiteSpace(item.Overview))
+            {
+                return false;
+            }
+            if (!item.ProductionYear.HasValue)
+            {
+                return false;
+            }
+            return base.IsFullLocalMetadata(item);
+        }
     }
 }
diff --git a/MediaBrowser.Providers/Music/AlbumMetadataService.cs b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
index 11348361af..90248e4184 100644
--- a/MediaBrowser.Providers/Music/AlbumMetadataService.cs
+++ b/MediaBrowser.Providers/Music/AlbumMetadataService.cs
@@ -104,14 +104,15 @@ namespace MediaBrowser.Providers.Music
         {
             var updateType = ItemUpdateType.None;
             
-            var albumArtists = songs
+            var artists = songs
                 .SelectMany(i => i.AlbumArtists)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
+                .OrderBy(i => i)
                 .ToList();
 
-            if (!item.AlbumArtists.SequenceEqual(albumArtists, StringComparer.OrdinalIgnoreCase))
+            if (!item.AlbumArtists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
             {
-                item.AlbumArtists = albumArtists;
+                item.AlbumArtists = artists;
                 updateType = updateType | ItemUpdateType.MetadataEdit;
             }
 
@@ -122,14 +123,15 @@ namespace MediaBrowser.Providers.Music
         {
             var updateType = ItemUpdateType.None;
 
-            var currentList = item.Artists.ToList();
-
-            item.Artists = songs.SelectMany(i => i.Artists)
+            var artists = songs
+                .SelectMany(i => i.Artists)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
+                .OrderBy(i => i)
                 .ToList();
 
-            if (currentList.Count != item.Artists.Count || !currentList.OrderBy(i => i).SequenceEqual(item.Artists.OrderBy(i => i), StringComparer.OrdinalIgnoreCase))
+            if (!item.Artists.SequenceEqual(artists, StringComparer.OrdinalIgnoreCase))
             {
+                item.Artists = artists;
                 updateType = updateType | ItemUpdateType.MetadataEdit;
             }
 
diff --git a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
index 758d0a6bd9..7f804f9df4 100644
--- a/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
+++ b/MediaBrowser.Providers/Omdb/OmdbImageProvider.cs
@@ -3,6 +3,7 @@ using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Entities;
@@ -108,6 +109,13 @@ namespace MediaBrowser.Providers.Omdb
                 }
             }
 
+            // Supports images for tv movies
+            var tvProgram = item as LiveTvProgram;
+            if (tvProgram != null && tvProgram.IsMovie)
+            {
+                return true;
+            }
+
             return item is Movie;
         }
 
diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs
index 3eaef59fbe..b635d4ead4 100644
--- a/MediaBrowser.Providers/Photos/PhotoProvider.cs
+++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -18,12 +17,10 @@ namespace MediaBrowser.Providers.Photos
     public class PhotoProvider : ICustomMetadataProvider<Photo>, IHasItemChangeMonitor, IForcedProvider
     {
         private readonly ILogger _logger;
-        private readonly IImageProcessor _imageProcessor;
 
-        public PhotoProvider(ILogger logger, IImageProcessor imageProcessor)
+        public PhotoProvider(ILogger logger)
         {
             _logger = logger;
-            _imageProcessor = imageProcessor;
         }
 
         public Task<ItemUpdateType> FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken)
@@ -75,10 +72,13 @@ namespace MediaBrowser.Providers.Photos
                         }
                     }
                 }
-
+                
                 item.CameraMake = image.ImageTag.Make;
                 item.CameraModel = image.ImageTag.Model;
 
+                item.Width = image.Properties.PhotoWidth;
+                item.Height = image.Properties.PhotoHeight;
+
                 var rating = image.ImageTag.Rating;
                 if (rating.HasValue)
                 {
@@ -142,20 +142,6 @@ namespace MediaBrowser.Providers.Photos
                 _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path);
             }
 
-            var imageInfo = item.GetImageInfo(ImageType.Primary, 0);
-            
-            try
-            {
-                var size = _imageProcessor.GetImageSize(imageInfo.Path, imageInfo.DateModified);
-
-                item.Width = Convert.ToInt32(size.Width);
-                item.Height = Convert.ToInt32(size.Height);
-            }
-            catch
-            {
-
-            } 
-
             const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport;
             return Task.FromResult(result);
         }
diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
index bbffd91b7c..a5b12dad23 100644
--- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
+++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
@@ -57,7 +57,9 @@ namespace MediaBrowser.Providers.TV
             return new List<ImageType>
             {
                 ImageType.Backdrop, 
-                ImageType.Thumb
+                ImageType.Thumb,
+                ImageType.Banner,
+                ImageType.Primary
             };
         }
 
@@ -152,6 +154,8 @@ namespace MediaBrowser.Providers.TV
 
         private void AddImages(List<RemoteImageInfo> list, FanartSeriesProvider.RootObject obj, int seasonNumber, CancellationToken cancellationToken)
         {
+            PopulateImages(list, obj.seasonposter, ImageType.Primary, 1000, 1426, seasonNumber);
+            PopulateImages(list, obj.seasonbanner, ImageType.Primary, 1000, 185, seasonNumber);
             PopulateImages(list, obj.seasonthumb, ImageType.Thumb, 500, 281, seasonNumber);
             PopulateImages(list, obj.showbackground, ImageType.Backdrop, 1920, 1080, seasonNumber);
         }
diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
index e512e6af81..6af2aa38db 100644
--- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs
@@ -1,5 +1,4 @@
-using System.Net;
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
@@ -18,6 +17,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Linq;
+using System.Net;
 using System.Threading;
 using System.Threading.Tasks;
 
diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
index df06525c1f..a5959f0b75 100644
--- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs
+++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs
@@ -74,5 +74,22 @@ namespace MediaBrowser.Providers.TV
                 await provider.Run(item, CancellationToken.None).ConfigureAwait(false);
             }
         }
+
+        protected override bool IsFullLocalMetadata(Series item)
+        {
+            if (string.IsNullOrWhiteSpace(item.Name))
+            {
+                return false;
+            }
+            if (string.IsNullOrWhiteSpace(item.Overview))
+            {
+                return false;
+            }
+            if (!item.ProductionYear.HasValue)
+            {
+                return false;
+            }
+            return base.IsFullLocalMetadata(item);
+        }
     }
 }
diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
index 0f7a9f7d8c..c644da0b82 100644
--- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
+++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
@@ -52,17 +52,16 @@ namespace MediaBrowser.Providers.TV
             Current = this;
         }
 
-        private const string RootUrl = "http://www.thetvdb.com/api/";
-        private const string SeriesQuery = "GetSeries.php?seriesname={0}";
+        private const string SeriesSearchUrl = "http://www.thetvdb.com/api/GetSeries.php?seriesname={0}&language={1}";
         private const string SeriesGetZip = "http://www.thetvdb.com/api/{0}/series/{1}/all/{2}.zip";
 
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
         {
             var seriesId = searchInfo.GetProviderId(MetadataProviders.Tvdb);
 
-            if (string.IsNullOrEmpty(seriesId))
+            if (string.IsNullOrWhiteSpace(seriesId))
             {
-                return await FindSeries(searchInfo.Name, cancellationToken).ConfigureAwait(false);
+                return await FindSeries(searchInfo.Name, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
             }
 
             var metadata = await GetMetadata(searchInfo, cancellationToken).ConfigureAwait(false);
@@ -92,14 +91,14 @@ namespace MediaBrowser.Providers.TV
 
             var seriesId = itemId.GetProviderId(MetadataProviders.Tvdb);
 
-            if (string.IsNullOrEmpty(seriesId))
+            if (string.IsNullOrWhiteSpace(seriesId))
             {
                 seriesId = itemId.Identities
                                  .Where(id => id.Type == MetadataProviders.Tvdb.ToString())
                                  .Select(id => id.Id)
                                  .FirstOrDefault();
 
-                if (string.IsNullOrEmpty(seriesId))
+                if (string.IsNullOrWhiteSpace(seriesId))
                 {
                     var srch = await GetSearchResults(itemId, cancellationToken).ConfigureAwait(false);
 
@@ -114,7 +113,7 @@ namespace MediaBrowser.Providers.TV
 
             cancellationToken.ThrowIfCancellationRequested();
 
-            if (!string.IsNullOrEmpty(seriesId))
+            if (!string.IsNullOrWhiteSpace(seriesId))
             {
                 await EnsureSeriesInfo(seriesId, itemId.MetadataLanguage, cancellationToken).ConfigureAwait(false);
 
@@ -282,29 +281,30 @@ namespace MediaBrowser.Providers.TV
         /// Finds the series.
         /// </summary>
         /// <param name="name">The name.</param>
+        /// <param name="language">The language.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task{System.String}.</returns>
-        private async Task<IEnumerable<RemoteSearchResult>> FindSeries(string name, CancellationToken cancellationToken)
+        private async Task<IEnumerable<RemoteSearchResult>> FindSeries(string name, string language, CancellationToken cancellationToken)
         {
-            var results = (await FindSeriesInternal(name, cancellationToken).ConfigureAwait(false)).ToList();
+            var results = (await FindSeriesInternal(name, language, cancellationToken).ConfigureAwait(false)).ToList();
 
             if (results.Count == 0)
             {
                 var parsedName = _libraryManager.ParseName(name);
                 var nameWithoutYear = parsedName.Name;
 
-                if (!string.IsNullOrEmpty(nameWithoutYear) && !string.Equals(nameWithoutYear, name, StringComparison.OrdinalIgnoreCase))
+                if (!string.IsNullOrWhiteSpace(nameWithoutYear) && !string.Equals(nameWithoutYear, name, StringComparison.OrdinalIgnoreCase))
                 {
-                    results = (await FindSeriesInternal(nameWithoutYear, cancellationToken).ConfigureAwait(false)).ToList();
+                    results = (await FindSeriesInternal(nameWithoutYear, language, cancellationToken).ConfigureAwait(false)).ToList();
                 }
             }
 
             return results;
         }
 
-        private async Task<IEnumerable<RemoteSearchResult>> FindSeriesInternal(string name, CancellationToken cancellationToken)
+        private async Task<IEnumerable<RemoteSearchResult>> FindSeriesInternal(string name, string language, CancellationToken cancellationToken)
         {
-            var url = string.Format(RootUrl + SeriesQuery, WebUtility.UrlEncode(name));
+            var url = string.Format(SeriesSearchUrl, WebUtility.UrlEncode(name), language.ToLower());
             var doc = new XmlDocument();
 
             using (var results = await _httpClient.Get(new HttpRequestOptions
@@ -683,7 +683,7 @@ namespace MediaBrowser.Providers.TV
 
             personInfo.Type = PersonType.Actor;
 
-            if (!string.IsNullOrEmpty(personInfo.Name))
+            if (!string.IsNullOrWhiteSpace(personInfo.Name))
             {
                 series.AddPerson(personInfo);
             }
@@ -1057,7 +1057,7 @@ namespace MediaBrowser.Providers.TV
             }
 
             var hasEpisodeChanged = true;
-            if (!string.IsNullOrEmpty(lastUpdateString) && lastTvDbUpdateTime.HasValue)
+            if (!string.IsNullOrWhiteSpace(lastUpdateString) && lastTvDbUpdateTime.HasValue)
             {
                 long num;
                 if (long.TryParse(lastUpdateString, NumberStyles.Any, _usCulture, out num))
@@ -1217,7 +1217,7 @@ namespace MediaBrowser.Providers.TV
                 }
             }
 
-            if (!string.IsNullOrEmpty(tvdbId))
+            if (!string.IsNullOrWhiteSpace(tvdbId))
             {
                 return new SeriesIdentity { Type = MetadataProviders.Tvdb.ToString(), Id = tvdbId };
             }
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index 2b17442dea..f0f30229ec 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -1400,7 +1400,9 @@ namespace MediaBrowser.Server.Implementations.Channels
         public async Task<Folder> GetInternalChannelFolder(string userId, CancellationToken cancellationToken)
         {
             var name = _localization.GetLocalizedString("ViewTypeChannels");
-            return await _libraryManager.GetNamedView(name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false);
+            var user = _userManager.GetUserById(userId);
+
+            return await _libraryManager.GetNamedView(user, name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false);
         }
 
         public async Task DownloadChannelItem(IChannelMediaItem item, string destination,
diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
index 27ec6cc3b1..80a7c50d19 100644
--- a/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Collections/CollectionImageProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
@@ -13,10 +14,9 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Collections
 {
-    public class CollectionImageProvider : BaseDynamicImageProvider<BoxSet>, ICustomMetadataProvider<BoxSet>
+    public class CollectionImageProvider : BaseDynamicImageProvider<BoxSet>
     {
-        public CollectionImageProvider(IFileSystem fileSystem, IProviderManager providerManager)
-            : base(fileSystem, providerManager)
+        public CollectionImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
         {
         }
 
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
index 52c21af686..be0b325487 100644
--- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
+++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Security;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Connect;
@@ -38,6 +39,7 @@ namespace MediaBrowser.Server.Implementations.Connect
         private readonly IServerConfigurationManager _config;
         private readonly IUserManager _userManager;
         private readonly IProviderManager _providerManager;
+        private readonly ISecurityManager _securityManager;
 
         private ConnectData _data = new ConnectData();
 
@@ -102,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Connect
             IEncryptionManager encryption,
             IHttpClient httpClient,
             IServerApplicationHost appHost,
-            IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager)
+            IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager)
         {
             _logger = logger;
             _appPaths = appPaths;
@@ -113,6 +115,7 @@ namespace MediaBrowser.Server.Implementations.Connect
             _config = config;
             _userManager = userManager;
             _providerManager = providerManager;
+            _securityManager = securityManager;
 
             _userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated;
             _config.ConfigurationUpdated += _config_ConfigurationUpdated;
@@ -1054,6 +1057,90 @@ namespace MediaBrowser.Server.Implementations.Connect
             }
         }
 
+        public async Task<ConnectSupporterSummary> GetConnectSupporterSummary()
+        {
+            if (!_securityManager.IsMBSupporter)
+            {
+                return new ConnectSupporterSummary();
+            }
+
+            var url = GetConnectUrl("keyAssociation");
+
+            url += "?serverId=" + ConnectServerId;
+            url += "&supporterKey=" + _securityManager.SupporterKey;
+
+            var options = new HttpRequestOptions
+            {
+                Url = url,
+                CancellationToken = CancellationToken.None
+            };
+
+            SetServerAccessToken(options);
+            SetApplicationHeader(options);
+
+            // No need to examine the response
+            using (var stream = (await _httpClient.SendAsync(options, "GET").ConfigureAwait(false)).Content)
+            {
+                return _json.DeserializeFromStream<ConnectSupporterSummary>(stream);
+            }
+        }
+
+        public async Task AddConnectSupporter(string id)
+        {
+            if (!_securityManager.IsMBSupporter)
+            {
+                throw new InvalidOperationException();
+            }
+
+            var url = GetConnectUrl("keyAssociation");
+
+            url += "?serverId=" + ConnectServerId;
+            url += "&supporterKey=" + _securityManager.SupporterKey;
+            url += "&userId=" + id;
+
+            var options = new HttpRequestOptions
+            {
+                Url = url,
+                CancellationToken = CancellationToken.None
+            };
+
+            SetServerAccessToken(options);
+            SetApplicationHeader(options);
+
+            // No need to examine the response
+            using (var stream = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content)
+            {
+            }
+        }
+
+        public async Task RemoveConnectSupporter(string id)
+        {
+            if (!_securityManager.IsMBSupporter)
+            {
+                throw new InvalidOperationException();
+            }
+
+            var url = GetConnectUrl("keyAssociation");
+
+            url += "?serverId=" + ConnectServerId;
+            url += "&supporterKey=" + _securityManager.SupporterKey;
+            url += "&userId=" + id;
+     
+            var options = new HttpRequestOptions
+            {
+                Url = url,
+                CancellationToken = CancellationToken.None
+            };
+
+            SetServerAccessToken(options);
+            SetApplicationHeader(options);
+
+            // No need to examine the response
+            using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content)
+            {
+            }
+        }
+
         public async Task Authenticate(string username, string passwordMd5)
         {
             if (string.IsNullOrWhiteSpace(username))
diff --git a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
index 2fe5d8f742..566f4c5f40 100644
--- a/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
+++ b/MediaBrowser.Server.Implementations/Devices/CameraUploadsFolder.cs
@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Entities;
+using System;
 using System.IO;
 using System.Linq;
 
@@ -14,6 +15,11 @@ namespace MediaBrowser.Server.Implementations.Devices
 
         public override bool IsVisible(User user)
         {
+            if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase))
+            {
+                return false;
+            }
+            
             return GetChildren(user, true).Any() &&
                 base.IsVisible(user);
         }
diff --git a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
index 3211f88d5f..b65b7d11b3 100644
--- a/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
+++ b/MediaBrowser.Server.Implementations/Devices/DeviceManager.cs
@@ -44,7 +44,7 @@ namespace MediaBrowser.Server.Implementations.Devices
             _logger = logger;
         }
 
-        public async Task<DeviceInfo> RegisterDevice(string reportedId, string name, string appName, string usedByUserId)
+        public async Task<DeviceInfo> RegisterDevice(string reportedId, string name, string appName, string appVersion, string usedByUserId)
         {
             var device = GetDevice(reportedId) ?? new DeviceInfo
             {
@@ -53,6 +53,7 @@ namespace MediaBrowser.Server.Implementations.Devices
 
             device.ReportedName = name;
             device.AppName = appName;
+            device.AppVersion = appVersion;
 
             if (!string.IsNullOrWhiteSpace(usedByUserId))
             {
@@ -109,7 +110,7 @@ namespace MediaBrowser.Server.Implementations.Devices
                 devices = devices.Where(i =>
                 {
                     var caps = GetCapabilities(i.Id);
-                    var deviceVal = caps.SupportsUniqueIdentifier ?? caps.SupportsPersistentIdentifier;
+                    var deviceVal = caps.SupportsPersistentIdentifier;
                     return deviceVal == val;
                 });
             }
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageExtensions.cs b/MediaBrowser.Server.Implementations/Drawing/ImageExtensions.cs
deleted file mode 100644
index 28ea26a322..0000000000
--- a/MediaBrowser.Server.Implementations/Drawing/ImageExtensions.cs
+++ /dev/null
@@ -1,220 +0,0 @@
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
-using System.IO;
-
-namespace MediaBrowser.Server.Implementations.Drawing
-{
-    /// <summary>
-    /// Class ImageExtensions
-    /// </summary>
-    public static class ImageExtensions
-    {
-        /// <summary>
-        /// Saves the image.
-        /// </summary>
-        /// <param name="outputFormat">The output format.</param>
-        /// <param name="image">The image.</param>
-        /// <param name="toStream">To stream.</param>
-        /// <param name="quality">The quality.</param>
-        public static void Save(this Image image, ImageFormat outputFormat, Stream toStream, int quality)
-        {
-            // Use special save methods for jpeg and png that will result in a much higher quality image
-            // All other formats use the generic Image.Save
-            if (ImageFormat.Jpeg.Equals(outputFormat))
-            {
-                SaveAsJpeg(image, toStream, quality);
-            }
-            else if (ImageFormat.Png.Equals(outputFormat))
-            {
-                image.Save(toStream, ImageFormat.Png);
-            }
-            else
-            {
-                image.Save(toStream, outputFormat);
-            }
-        }
-
-        /// <summary>
-        /// Saves the JPEG.
-        /// </summary>
-        /// <param name="image">The image.</param>
-        /// <param name="target">The target.</param>
-        /// <param name="quality">The quality.</param>
-        public static void SaveAsJpeg(this Image image, Stream target, int quality)
-        {
-            using (var encoderParameters = new EncoderParameters(1))
-            {
-                encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
-                image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters);
-            }
-        }
-
-        private static readonly ImageCodecInfo[] Encoders = ImageCodecInfo.GetImageEncoders();
-
-        /// <summary>
-        /// Gets the image codec info.
-        /// </summary>
-        /// <param name="mimeType">Type of the MIME.</param>
-        /// <returns>ImageCodecInfo.</returns>
-        private static ImageCodecInfo GetImageCodecInfo(string mimeType)
-        {
-            foreach (var encoder in Encoders)
-            {
-                if (string.Equals(encoder.MimeType, mimeType, StringComparison.OrdinalIgnoreCase))
-                {
-                    return encoder;
-                }
-            }
-
-            return Encoders.Length == 0 ? null : Encoders[0];
-        }
-
-        /// <summary>
-        /// Crops an image by removing whitespace and transparency from the edges
-        /// </summary>
-        /// <param name="bmp">The BMP.</param>
-        /// <returns>Bitmap.</returns>
-        /// <exception cref="System.Exception"></exception>
-        public static Bitmap CropWhitespace(this Bitmap bmp)
-        {
-            var width = bmp.Width;
-            var height = bmp.Height;
-
-            var topmost = 0;
-            for (int row = 0; row < height; ++row)
-            {
-                if (IsAllWhiteRow(bmp, row, width))
-                    topmost = row;
-                else break;
-            }
-
-            int bottommost = 0;
-            for (int row = height - 1; row >= 0; --row)
-            {
-                if (IsAllWhiteRow(bmp, row, width))
-                    bottommost = row;
-                else break;
-            }
-
-            int leftmost = 0, rightmost = 0;
-            for (int col = 0; col < width; ++col)
-            {
-                if (IsAllWhiteColumn(bmp, col, height))
-                    leftmost = col;
-                else
-                    break;
-            }
-
-            for (int col = width - 1; col >= 0; --col)
-            {
-                if (IsAllWhiteColumn(bmp, col, height))
-                    rightmost = col;
-                else
-                    break;
-            }
-
-            if (rightmost == 0) rightmost = width; // As reached left
-            if (bottommost == 0) bottommost = height; // As reached top.
-
-            var croppedWidth = rightmost - leftmost;
-            var croppedHeight = bottommost - topmost;
-
-            if (croppedWidth == 0) // No border on left or right
-            {
-                leftmost = 0;
-                croppedWidth = width;
-            }
-
-            if (croppedHeight == 0) // No border on top or bottom
-            {
-                topmost = 0;
-                croppedHeight = height;
-            }
-
-            // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
-            var thumbnail = new Bitmap(croppedWidth, croppedHeight, PixelFormat.Format32bppPArgb);
-
-            // Preserve the original resolution
-            TrySetResolution(thumbnail, bmp.HorizontalResolution, bmp.VerticalResolution);
-
-            using (var thumbnailGraph = Graphics.FromImage(thumbnail))
-            {
-                thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
-                thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
-                thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
-                thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
-                thumbnailGraph.CompositingMode = CompositingMode.SourceCopy;
-
-                thumbnailGraph.DrawImage(bmp,
-                  new RectangleF(0, 0, croppedWidth, croppedHeight),
-                  new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
-                  GraphicsUnit.Pixel);
-            }
-            return thumbnail;
-        }
-
-        /// <summary>
-        /// Tries the set resolution.
-        /// </summary>
-        /// <param name="bmp">The BMP.</param>
-        /// <param name="x">The x.</param>
-        /// <param name="y">The y.</param>
-        private static void TrySetResolution(Bitmap bmp, float x, float y)
-        {
-            if (x > 0 && y > 0)
-            {
-                bmp.SetResolution(x, y);
-            }
-        }
-
-        /// <summary>
-        /// Determines whether or not a row of pixels is all whitespace
-        /// </summary>
-        /// <param name="bmp">The BMP.</param>
-        /// <param name="row">The row.</param>
-        /// <param name="width">The width.</param>
-        /// <returns><c>true</c> if [is all white row] [the specified BMP]; otherwise, <c>false</c>.</returns>
-        private static bool IsAllWhiteRow(Bitmap bmp, int row, int width)
-        {
-            for (var i = 0; i < width; ++i)
-            {
-                if (!IsWhiteSpace(bmp.GetPixel(i, row)))
-                {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// Determines whether or not a column of pixels is all whitespace
-        /// </summary>
-        /// <param name="bmp">The BMP.</param>
-        /// <param name="col">The col.</param>
-        /// <param name="height">The height.</param>
-        /// <returns><c>true</c> if [is all white column] [the specified BMP]; otherwise, <c>false</c>.</returns>
-        private static bool IsAllWhiteColumn(Bitmap bmp, int col, int height)
-        {
-            for (var i = 0; i < height; ++i)
-            {
-                if (!IsWhiteSpace(bmp.GetPixel(col, i)))
-                {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// Determines if a color is whitespace
-        /// </summary>
-        /// <param name="color">The color.</param>
-        /// <returns><c>true</c> if [is white space] [the specified color]; otherwise, <c>false</c>.</returns>
-        private static bool IsWhiteSpace(Color color)
-        {
-            return (color.R == 255 && color.G == 255 && color.B == 255) || color.A == 0;
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs b/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs
index e9c67bf48a..7117482c8a 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs
@@ -46,41 +46,11 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// <exception cref="ArgumentException">The image was of an unrecognised format.</exception>
         public static ImageSize GetDimensions(string path, ILogger logger, IFileSystem fileSystem)
         {
-            try
+            using (var fs = File.OpenRead(path))
             {
-                using (var fs = File.OpenRead(path))
+                using (var binaryReader = new BinaryReader(fs))
                 {
-                    using (var binaryReader = new BinaryReader(fs))
-                    {
-                        return GetDimensions(binaryReader);
-                    }
-                }
-            }
-            catch
-            {
-                logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
-            }
-
-            // Buffer to memory stream to avoid image locking file
-            using (var fs = fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
-            {
-                using (var memoryStream = new MemoryStream())
-                {
-                    fs.CopyTo(memoryStream);
-
-                    memoryStream.Position = 0;
-
-                    // Co it the old fashioned way
-                    using (var b = System.Drawing.Image.FromStream(memoryStream, true, false))
-                    {
-                        var size = b.Size;
-
-                        return new ImageSize
-                        {
-                            Width = size.Width,
-                            Height = size.Height
-                        };
-                    }
+                    return GetDimensions(binaryReader);
                 }
             }
         }
diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
index 5055d2750f..79e5a0cf00 100644
--- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
@@ -1,10 +1,9 @@
-using Imazen.WebP;
+using ImageMagickSharp;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
@@ -13,9 +12,6 @@ using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
 using System.Globalization;
 using System.IO;
 using System.Linq;
@@ -54,14 +50,12 @@ namespace MediaBrowser.Server.Implementations.Drawing
         private readonly IFileSystem _fileSystem;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IServerApplicationPaths _appPaths;
-        private readonly IMediaEncoder _mediaEncoder;
 
-        public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer, IMediaEncoder mediaEncoder)
+        public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem, IJsonSerializer jsonSerializer)
         {
             _logger = logger;
             _fileSystem = fileSystem;
             _jsonSerializer = jsonSerializer;
-            _mediaEncoder = mediaEncoder;
             _appPaths = appPaths;
 
             _saveImageSizeTimer = new Timer(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite);
@@ -92,7 +86,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             _cachedImagedSizes = new ConcurrentDictionary<Guid, ImageSize>(sizeDictionary);
 
-            LogWebPVersion();
+            LogImageMagickVersionVersion();
         }
 
         private string ResizedImageCachePath
@@ -134,13 +128,46 @@ namespace MediaBrowser.Server.Implementations.Drawing
             }
         }
 
-        public Model.Drawing.ImageFormat[] GetSupportedImageOutputFormats()
+        public ImageFormat[] GetSupportedImageOutputFormats()
         {
             if (_webpAvailable)
             {
-                return new[] { Model.Drawing.ImageFormat.Webp, Model.Drawing.ImageFormat.Gif, Model.Drawing.ImageFormat.Jpg, Model.Drawing.ImageFormat.Png };
+                return new[] { ImageFormat.Webp, ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
             }
-            return new[] { Model.Drawing.ImageFormat.Gif, Model.Drawing.ImageFormat.Jpg, Model.Drawing.ImageFormat.Png };
+            return new[] { ImageFormat.Gif, ImageFormat.Jpg, ImageFormat.Png };
+        }
+
+        private bool _webpAvailable = true;
+        private void TestWebp()
+        {
+            try
+            {
+                var tmpPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".webp");
+                Directory.CreateDirectory(Path.GetDirectoryName(tmpPath));
+                
+                using (var wand = new MagickWand(1, 1, new PixelWand("none", 1)))
+                {
+                    wand.SaveImage(tmpPath);
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error loading webp: ", ex);
+                _webpAvailable = false;
+            }
+        }
+
+        private void LogImageMagickVersionVersion()
+        {
+            try
+            {
+                _logger.Info("ImageMagick version: " + Wand.VersionString);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error loading ImageMagick: ", ex);
+            }
+            TestWebp();
         }
 
         public async Task<string> ProcessImage(ImageProcessingOptions options)
@@ -189,7 +216,8 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             var quality = options.Quality ?? 90;
 
-            var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, options.OutputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
+            var outputFormat = GetOutputFormat(options.OutputFormat);
+            var cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.BackgroundColor);
 
             var semaphore = GetLock(cacheFilePath);
 
@@ -212,77 +240,44 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                var hasPostProcessing = !string.IsNullOrEmpty(options.BackgroundColor) || options.UnplayedCount.HasValue || options.AddPlayedIndicator || options.PercentPlayed > 0;
+                CheckDisposed();
+
+                var newWidth = Convert.ToInt32(newSize.Width);
+                var newHeight = Convert.ToInt32(newSize.Height);
 
-                using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
+                Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
+
+                if (string.IsNullOrWhiteSpace(options.BackgroundColor))
                 {
-                    // Copy to memory stream to avoid Image locking file
-                    using (var memoryStream = new MemoryStream())
+                    using (var originalImage = new MagickWand(originalImagePath))
                     {
-                        await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
+                        originalImage.CurrentImage.ResizeImage(newWidth, newHeight);
+
+                        DrawIndicator(originalImage, newWidth, newHeight, options);
 
-                        using (var originalImage = Image.FromStream(memoryStream, true, false))
+                        originalImage.CurrentImage.CompressionQuality = quality;
+
+                        originalImage.SaveImage(cacheFilePath);
+
+                        return cacheFilePath;
+                    }
+                }
+                else
+                {
+                    using (var wand = new MagickWand(newWidth, newHeight, options.BackgroundColor))
+                    {
+                        using (var originalImage = new MagickWand(originalImagePath))
                         {
-                            var newWidth = Convert.ToInt32(newSize.Width);
-                            var newHeight = Convert.ToInt32(newSize.Height);
-
-                            var selectedOutputFormat = options.OutputFormat;
-
-                            _logger.Debug("Processing image to {0}", selectedOutputFormat);
-
-                            // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
-                            // Also, Webp only supports Format32bppArgb and Format32bppRgb
-                            var pixelFormat = selectedOutputFormat == Model.Drawing.ImageFormat.Webp
-                                ? PixelFormat.Format32bppArgb
-                                : PixelFormat.Format32bppPArgb;
-
-                            using (var thumbnail = new Bitmap(newWidth, newHeight, pixelFormat))
-                            {
-                                // Mono throw an exeception if assign 0 to SetResolution
-                                if (originalImage.HorizontalResolution > 0 && originalImage.VerticalResolution > 0)
-                                {
-                                    // Preserve the original resolution
-                                    thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
-                                }
-
-                                using (var thumbnailGraph = Graphics.FromImage(thumbnail))
-                                {
-                                    thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
-                                    thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
-                                    thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
-                                    thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
-                                    thumbnailGraph.CompositingMode = !hasPostProcessing ?
-                                        CompositingMode.SourceCopy :
-                                        CompositingMode.SourceOver;
-
-                                    SetBackgroundColor(thumbnailGraph, options);
-
-                                    thumbnailGraph.DrawImage(originalImage, 0, 0, newWidth, newHeight);
-
-                                    DrawIndicator(thumbnailGraph, newWidth, newHeight, options);
-
-                                    var outputFormat = GetOutputFormat(originalImage, selectedOutputFormat);
-
-                                    Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
-
-                                    // Save to the cache location
-                                    using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
-                                    {
-                                        if (selectedOutputFormat == Model.Drawing.ImageFormat.Webp)
-                                        {
-                                            SaveToWebP(thumbnail, cacheFileStream, quality);
-                                        }
-                                        else
-                                        {
-                                            // Save to the memory stream
-                                            thumbnail.Save(outputFormat, cacheFileStream, quality);
-                                        }
-                                    }
-
-                                    return cacheFilePath;
-                                }
-                            }
+                            originalImage.CurrentImage.ResizeImage(newWidth, newHeight);
+
+                            wand.CurrentImage.CompositeImage(originalImage, CompositeOperator.OverCompositeOp, 0, 0);
+                            DrawIndicator(wand, newWidth, newHeight, options);
+
+                            wand.CurrentImage.CompressionQuality = quality;
 
+                            wand.SaveImage(cacheFilePath);
+
+                            return cacheFilePath;
                         }
                     }
                 }
@@ -293,59 +288,24 @@ namespace MediaBrowser.Server.Implementations.Drawing
             }
         }
 
-        private void SaveToWebP(Bitmap thumbnail, Stream toStream, int quality)
-        {
-            new SimpleEncoder().Encode(thumbnail, toStream, quality);
-        }
-
-        private bool _webpAvailable = true;
-        private void LogWebPVersion()
+        private ImageFormat GetOutputFormat(ImageFormat requestedFormat)
         {
-            try
+            if (requestedFormat == ImageFormat.Webp && !_webpAvailable)
             {
-                _logger.Info("libwebp version: " + SimpleEncoder.GetEncoderVersion());
+                return ImageFormat.Png;
             }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error loading libwebp: ", ex);
-                _webpAvailable = false;
-            }
-        }
-
-        /// <summary>
-        /// Sets the color of the background.
-        /// </summary>
-        /// <param name="graphics">The graphics.</param>
-        /// <param name="options">The options.</param>
-        private void SetBackgroundColor(Graphics graphics, ImageProcessingOptions options)
-        {
-            var color = options.BackgroundColor;
 
-            if (!string.IsNullOrEmpty(color))
-            {
-                Color drawingColor;
-
-                try
-                {
-                    drawingColor = ColorTranslator.FromHtml(color);
-                }
-                catch
-                {
-                    drawingColor = ColorTranslator.FromHtml("#" + color);
-                }
-
-                graphics.Clear(drawingColor);
-            }
+            return requestedFormat;
         }
 
         /// <summary>
         /// Draws the indicator.
         /// </summary>
-        /// <param name="graphics">The graphics.</param>
+        /// <param name="wand">The wand.</param>
         /// <param name="imageWidth">Width of the image.</param>
         /// <param name="imageHeight">Height of the image.</param>
         /// <param name="options">The options.</param>
-        private void DrawIndicator(Graphics graphics, int imageWidth, int imageHeight, ImageProcessingOptions options)
+        private void DrawIndicator(MagickWand wand, int imageWidth, int imageHeight, ImageProcessingOptions options)
         {
             if (!options.AddPlayedIndicator && !options.UnplayedCount.HasValue && options.PercentPlayed.Equals(0))
             {
@@ -356,22 +316,20 @@ namespace MediaBrowser.Server.Implementations.Drawing
             {
                 if (options.AddPlayedIndicator)
                 {
-                    var currentImageSize = new Size(imageWidth, imageHeight);
+                    var currentImageSize = new ImageSize(imageWidth, imageHeight);
 
-                    new PlayedIndicatorDrawer().DrawPlayedIndicator(graphics, currentImageSize);
+                    new PlayedIndicatorDrawer(_appPaths).DrawPlayedIndicator(wand, currentImageSize);
                 }
                 else if (options.UnplayedCount.HasValue)
                 {
-                    var currentImageSize = new Size(imageWidth, imageHeight);
+                    var currentImageSize = new ImageSize(imageWidth, imageHeight);
 
-                    new UnplayedCountIndicator().DrawUnplayedCountIndicator(graphics, currentImageSize, options.UnplayedCount.Value);
+                    new UnplayedCountIndicator(_appPaths).DrawUnplayedCountIndicator(wand, currentImageSize, options.UnplayedCount.Value);
                 }
 
                 if (options.PercentPlayed > 0)
                 {
-                    var currentImageSize = new Size(imageWidth, imageHeight);
-
-                    new PercentPlayedDrawer().Process(graphics, currentImageSize, options.PercentPlayed);
+                    new PercentPlayedDrawer().Process(wand, options.PercentPlayed);
                 }
             }
             catch (Exception ex)
@@ -380,29 +338,6 @@ namespace MediaBrowser.Server.Implementations.Drawing
             }
         }
 
-        /// <summary>
-        /// Gets the output format.
-        /// </summary>
-        /// <param name="image">The image.</param>
-        /// <param name="outputFormat">The output format.</param>
-        /// <returns>ImageFormat.</returns>
-        private System.Drawing.Imaging.ImageFormat GetOutputFormat(Image image, Model.Drawing.ImageFormat outputFormat)
-        {
-            switch (outputFormat)
-            {
-                case Model.Drawing.ImageFormat.Bmp:
-                    return System.Drawing.Imaging.ImageFormat.Bmp;
-                case Model.Drawing.ImageFormat.Gif:
-                    return System.Drawing.Imaging.ImageFormat.Gif;
-                case Model.Drawing.ImageFormat.Jpg:
-                    return System.Drawing.Imaging.ImageFormat.Jpeg;
-                case Model.Drawing.ImageFormat.Png:
-                    return System.Drawing.Imaging.ImageFormat.Png;
-                default:
-                    return image.RawFormat;
-            }
-        }
-
         /// <summary>
         /// Crops whitespace from an image, caches the result, and returns the cached path
         /// </summary>
@@ -429,28 +364,12 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
-                {
-                    // Copy to memory stream to avoid Image locking file
-                    using (var memoryStream = new MemoryStream())
-                    {
-                        await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
-                        using (var originalImage = (Bitmap)Image.FromStream(memoryStream, true, false))
-                        {
-                            var outputFormat = originalImage.RawFormat;
+                Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath));
 
-                            using (var croppedImage = originalImage.CropWhitespace())
-                            {
-                                Directory.CreateDirectory(Path.GetDirectoryName(croppedImagePath));
-
-                                using (var outputStream = _fileSystem.GetFileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
-                                {
-                                    croppedImage.Save(outputFormat, outputStream, 100);
-                                }
-                            }
-                        }
-                    }
+                using (var wand = new MagickWand(originalImagePath))
+                {
+                    wand.CurrentImage.TrimImage(10);
+                    wand.SaveImage(croppedImagePath);
                 }
             }
             catch (Exception ex)
@@ -469,14 +388,14 @@ namespace MediaBrowser.Server.Implementations.Drawing
         }
 
         /// <summary>
-        /// Increment this when indicator drawings change
+        /// Increment this when there's a change requiring caches to be invalidated
         /// </summary>
-        private const string IndicatorVersion = "2";
+        private const string Version = "3";
 
         /// <summary>
         /// Gets the cache file path based on a set of parameters
         /// </summary>
-        private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, Model.Drawing.ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
+        private string GetCacheFilePath(string originalPath, ImageSize outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, string backgroundColor)
         {
             var filename = originalPath;
 
@@ -490,29 +409,19 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             filename += "f=" + format;
 
-            var hasIndicator = false;
-
             if (addPlayedIndicator)
             {
                 filename += "pl=true";
-                hasIndicator = true;
             }
 
             if (percentPlayed > 0)
             {
                 filename += "p=" + percentPlayed;
-                hasIndicator = true;
             }
 
             if (unwatchedCount.HasValue)
             {
                 filename += "p=" + unwatchedCount.Value;
-                hasIndicator = true;
-            }
-
-            if (hasIndicator)
-            {
-                filename += "iv=" + IndicatorVersion;
             }
 
             if (!string.IsNullOrEmpty(backgroundColor))
@@ -520,6 +429,8 @@ namespace MediaBrowser.Server.Implementations.Drawing
                 filename += "b=" + backgroundColor;
             }
 
+            filename += "v=" + Version;
+
             return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower());
         }
 
@@ -533,6 +444,11 @@ namespace MediaBrowser.Server.Implementations.Drawing
             return GetImageSize(path, File.GetLastWriteTimeUtc(path));
         }
 
+        public ImageSize GetImageSize(ItemImageInfo info)
+        {
+            return GetImageSize(info.Path, info.DateModified);
+        }
+
         /// <summary>
         /// Gets the size of the image.
         /// </summary>
@@ -540,7 +456,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// <param name="imageDateModified">The image date modified.</param>
         /// <returns>ImageSize.</returns>
         /// <exception cref="System.ArgumentNullException">path</exception>
-        public ImageSize GetImageSize(string path, DateTime imageDateModified)
+        private ImageSize GetImageSize(string path, DateTime imageDateModified)
         {
             if (string.IsNullOrEmpty(path))
             {
@@ -570,11 +486,34 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// <returns>ImageSize.</returns>
         private ImageSize GetImageSizeInternal(string path)
         {
-            var size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
+            ImageSize size;
+
+            try
+            {
+                size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
+            }
+            catch
+            {
+                _logger.Info("Failed to read image header for {0}. Doing it the slow way.", path);
+
+                CheckDisposed();
+
+                using (var wand = new MagickWand())
+                {
+                    wand.PingImage(path);
+                    var img = wand.CurrentImage;
+
+                    size = new ImageSize
+                    {
+                        Width = img.Width,
+                        Height = img.Height
+                    };
+                }
+            }
 
             StartSaveImageSizeTimer();
 
-            return new ImageSize { Width = size.Width, Height = size.Height };
+            return size;
         }
 
         private readonly Timer _saveImageSizeTimer;
@@ -727,7 +666,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
         }
 
         /// <summary>
-        /// Runs an image through the image enhancers, caches the result, and returns the cached path
+        /// Gets the enhanced image internal.
         /// </summary>
         /// <param name="originalImagePath">The original image path.</param>
         /// <param name="item">The item.</param>
@@ -735,8 +674,12 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// <param name="imageIndex">Index of the image.</param>
         /// <param name="supportedEnhancers">The supported enhancers.</param>
         /// <param name="cacheGuid">The cache unique identifier.</param>
-        /// <returns>System.String.</returns>
-        /// <exception cref="System.ArgumentNullException">originalImagePath</exception>
+        /// <returns>Task&lt;System.String&gt;.</returns>
+        /// <exception cref="ArgumentNullException">
+        /// originalImagePath
+        /// or
+        /// item
+        /// </exception>
         private async Task<string> GetEnhancedImageInternal(string originalImagePath,
             IHasImages item,
             ImageType imageType,
@@ -770,51 +713,8 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
-                {
-                    // Copy to memory stream to avoid Image locking file
-                    using (var memoryStream = new MemoryStream())
-                    {
-                        await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
-                        memoryStream.Position = 0;
-
-                        var imageStream = new ImageStream
-                        {
-                            Stream = memoryStream,
-                            Format = GetFormat(originalImagePath)
-                        };
-
-                        //Pass the image through registered enhancers
-                        using (var newImageStream = await ExecuteImageEnhancers(supportedEnhancers, imageStream, item, imageType, imageIndex).ConfigureAwait(false))
-                        {
-                            var parentDirectory = Path.GetDirectoryName(enhancedImagePath);
-
-                            Directory.CreateDirectory(parentDirectory);
-
-                            // Save as png
-                            if (newImageStream.Format == Model.Drawing.ImageFormat.Png)
-                            {
-                                //And then save it in the cache
-                                using (var outputStream = _fileSystem.GetFileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
-                                {
-                                    await newImageStream.Stream.CopyToAsync(outputStream).ConfigureAwait(false);
-                                }
-                            }
-                            else
-                            {
-                                using (var newImage = Image.FromStream(newImageStream.Stream, true, false))
-                                {
-                                    //And then save it in the cache
-                                    using (var outputStream = _fileSystem.GetFileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
-                                    {
-                                        newImage.Save(System.Drawing.Imaging.ImageFormat.Png, outputStream, 100);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
+                Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
+                await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
             }
             finally
             {
@@ -824,43 +724,18 @@ namespace MediaBrowser.Server.Implementations.Drawing
             return enhancedImagePath;
         }
 
-        private Model.Drawing.ImageFormat GetFormat(string path)
-        {
-            var extension = Path.GetExtension(path);
-
-            if (string.Equals(extension, ".png", StringComparison.OrdinalIgnoreCase))
-            {
-                return Model.Drawing.ImageFormat.Png;
-            }
-            if (string.Equals(extension, ".gif", StringComparison.OrdinalIgnoreCase))
-            {
-                return Model.Drawing.ImageFormat.Gif;
-            }
-            if (string.Equals(extension, ".webp", StringComparison.OrdinalIgnoreCase))
-            {
-                return Model.Drawing.ImageFormat.Webp;
-            }
-            if (string.Equals(extension, ".bmp", StringComparison.OrdinalIgnoreCase))
-            {
-                return Model.Drawing.ImageFormat.Bmp;
-            }
-
-            return Model.Drawing.ImageFormat.Jpg;
-        }
-
         /// <summary>
         /// Executes the image enhancers.
         /// </summary>
         /// <param name="imageEnhancers">The image enhancers.</param>
-        /// <param name="originalImage">The original image.</param>
+        /// <param name="inputPath">The input path.</param>
+        /// <param name="outputPath">The output path.</param>
         /// <param name="item">The item.</param>
         /// <param name="imageType">Type of the image.</param>
         /// <param name="imageIndex">Index of the image.</param>
         /// <returns>Task{EnhancedImage}.</returns>
-        private async Task<ImageStream> ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, ImageStream originalImage, IHasImages item, ImageType imageType, int imageIndex)
+        private async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, IHasImages item, ImageType imageType, int imageIndex)
         {
-            var result = originalImage;
-
             // Run the enhancers sequentially in order of priority
             foreach (var enhancer in imageEnhancers)
             {
@@ -868,7 +743,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
                 try
                 {
-                    result = await enhancer.EnhanceImageAsync(item, result, imageType, imageIndex).ConfigureAwait(false);
+                    await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
                 }
                 catch (Exception ex)
                 {
@@ -876,9 +751,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
                     throw;
                 }
-            }
 
-            return result;
+                // Feed the output into the next enhancer as input
+                inputPath = outputPath;
+            }
         }
 
         /// <summary>
@@ -978,9 +854,20 @@ namespace MediaBrowser.Server.Implementations.Drawing
             });
         }
 
+        private bool _disposed;
         public void Dispose()
         {
+            _disposed = true;
+            Wand.CloseEnvironment();
             _saveImageSizeTimer.Dispose();
         }
+
+        private void CheckDisposed()
+        {
+            if (_disposed)
+            {
+                throw new ObjectDisposedException(GetType().Name);
+            }
+        }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs b/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
index 68f66e9772..20c2ab93be 100644
--- a/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/PercentPlayedDrawer.cs
@@ -1,5 +1,5 @@
-using System;
-using System.Drawing;
+using ImageMagickSharp;
+using System;
 
 namespace MediaBrowser.Server.Implementations.Drawing
 {
@@ -7,26 +7,32 @@ namespace MediaBrowser.Server.Implementations.Drawing
     {
         private const int IndicatorHeight = 8;
 
-        public void Process(Graphics graphics, Size imageSize, double percent)
+        public void Process(MagickWand wand, double percent)
         {
-            var y = imageSize.Height - IndicatorHeight;
+            var currentImage = wand.CurrentImage;
+            var height = currentImage.Height;
 
-            using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 0, 0, 0)))
+            using (var draw = new DrawingWand())
             {
-                const int innerX = 0;
-                var innerY = y;
-                var innerWidth = imageSize.Width;
-                var innerHeight = imageSize.Height;
+                using (PixelWand pixel = new PixelWand())
+                {
+                    var endX = currentImage.Width - 1;
+                    var endY = height - 1;
 
-                graphics.FillRectangle(backdroundBrush, innerX, innerY, innerWidth, innerHeight);
+                    pixel.Color = "black";
+                    pixel.Opacity = 0.4;
+                    draw.FillColor = pixel;
+                    draw.DrawRectangle(0, endY - IndicatorHeight, endX, endY);
 
-                using (var foregroundBrush = new SolidBrush(Color.FromArgb(82, 181, 75)))
-                {
-                    double foregroundWidth = innerWidth;
+                    double foregroundWidth = endX;
                     foregroundWidth *= percent;
                     foregroundWidth /= 100;
 
-                    graphics.FillRectangle(foregroundBrush, innerX, innerY, Convert.ToInt32(Math.Round(foregroundWidth)), innerHeight);
+                    pixel.Color = "#52B54B";
+                    pixel.Opacity = 0;
+                    draw.FillColor = pixel;
+                    draw.DrawRectangle(0, endY - IndicatorHeight, Convert.ToInt32(Math.Round(foregroundWidth)), endY);
+                    wand.CurrentImage.DrawImage(draw);
                 }
             }
         }
diff --git a/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs b/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs
index fa4231612b..359065cc2e 100644
--- a/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/PlayedIndicatorDrawer.cs
@@ -1,32 +1,86 @@
-using System.Drawing;
+using ImageMagickSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Drawing;
+using System;
+using System.IO;
 
 namespace MediaBrowser.Server.Implementations.Drawing
 {
     public class PlayedIndicatorDrawer
     {
-        private const int IndicatorHeight = 40;
-        public const int IndicatorWidth = 40;
-        private const int FontSize = 40;
-        private const int OffsetFromTopRightCorner = 10;
+        private const int FontSize = 52;
+        private const int OffsetFromTopRightCorner = 38;
 
-        public void DrawPlayedIndicator(Graphics graphics, Size imageSize)
+        private readonly IApplicationPaths _appPaths;
+
+        public PlayedIndicatorDrawer(IApplicationPaths appPaths)
+        {
+            _appPaths = appPaths;
+        }
+
+        public void DrawPlayedIndicator(MagickWand wand, ImageSize imageSize)
         {
-            var x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
+            var x = imageSize.Width - OffsetFromTopRightCorner;
 
-            using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 82, 181, 75)))
+            using (var draw = new DrawingWand())
             {
-                graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight);
+                using (PixelWand pixel = new PixelWand())
+                {
+                    pixel.Color = "#52B54B";
+                    pixel.Opacity = 0.2;
+                    draw.FillColor = pixel;
+                    draw.DrawCircle(x, OffsetFromTopRightCorner, x - 20, OffsetFromTopRightCorner - 20);
+
+                    pixel.Opacity = 0;
+                    pixel.Color = "white";
+                    draw.FillColor = pixel;
+                    draw.Font = ExtractFont("webdings.ttf", _appPaths);
+                    draw.FontSize = FontSize;
+                    draw.FontStyle = FontStyleType.NormalStyle;
+                    draw.TextAlignment = TextAlignType.CenterAlign;
+                    draw.FontWeight = FontWeightType.RegularStyle;
+                    draw.TextAntialias = true;
+                    draw.DrawAnnotation(x + 4, OffsetFromTopRightCorner + 14, "a");
 
-                x = imageSize.Width - 45 - OffsetFromTopRightCorner;
+                    draw.FillColor = pixel;
+                    wand.CurrentImage.DrawImage(draw);
+                }
+            }
+        }
 
-                using (var font = new Font("Webdings", FontSize, FontStyle.Regular, GraphicsUnit.Pixel))
+        internal static string ExtractFont(string name, IApplicationPaths paths)
+        {
+            var filePath = Path.Combine(paths.ProgramDataPath, "fonts", name);
+
+            if (File.Exists(filePath))
+            {
+                return filePath;
+            }
+
+            var namespacePath = typeof(PlayedIndicatorDrawer).Namespace + ".fonts." + name;
+            var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".ttf");
+            Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
+
+            using (var stream = typeof(PlayedIndicatorDrawer).Assembly.GetManifestResourceStream(namespacePath))
+            {
+                using (var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.Read))
                 {
-                    using (var fontBrush = new SolidBrush(Color.White))
-                    {
-                        graphics.DrawString("a", font, fontBrush, x, OffsetFromTopRightCorner - 2);
-                    }
+                    stream.CopyTo(fileStream);
                 }
             }
+
+            Directory.CreateDirectory(Path.GetDirectoryName(filePath));
+
+            try
+            {
+                File.Copy(tempPath, filePath, false);
+            }
+            catch (IOException)
+            {
+                
+            }
+
+            return tempPath;
         }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs b/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs
index 695c6390a7..71cced0416 100644
--- a/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs
+++ b/MediaBrowser.Server.Implementations/Drawing/UnplayedCountIndicator.cs
@@ -1,49 +1,69 @@
-using System.Drawing;
+using ImageMagickSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Drawing;
+using System.Globalization;
 
 namespace MediaBrowser.Server.Implementations.Drawing
 {
     public class UnplayedCountIndicator
     {
-        private const int IndicatorHeight = 41;
-        public const int IndicatorWidth = 41;
-        private const int OffsetFromTopRightCorner = 10;
+        private const int OffsetFromTopRightCorner = 38;
 
-        public void DrawUnplayedCountIndicator(Graphics graphics, Size imageSize, int count)
+        private readonly IApplicationPaths _appPaths;
+
+        public UnplayedCountIndicator(IApplicationPaths appPaths)
         {
-            var x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
+            _appPaths = appPaths;
+        }
 
-            using (var backdroundBrush = new SolidBrush(Color.FromArgb(225, 82, 181, 75)))
-            {
-                graphics.FillEllipse(backdroundBrush, x, OffsetFromTopRightCorner, IndicatorWidth, IndicatorHeight);
+        public void DrawUnplayedCountIndicator(MagickWand wand, ImageSize imageSize, int count)
+        {
+            var x = imageSize.Width - OffsetFromTopRightCorner;
+            var text = count.ToString(CultureInfo.InvariantCulture);
 
-                var text = count.ToString();
+            using (var draw = new DrawingWand())
+            {
+                using (PixelWand pixel = new PixelWand())
+                {
+                    pixel.Color = "#52B54B";
+                    pixel.Opacity = 0.2;
+                    draw.FillColor = pixel;
+                    draw.DrawCircle(x, OffsetFromTopRightCorner, x - 20, OffsetFromTopRightCorner - 20);
 
-                x = imageSize.Width - IndicatorWidth - OffsetFromTopRightCorner;
-                var y = OffsetFromTopRightCorner + 6;
-                var fontSize = 24;
+                    pixel.Opacity = 0;
+                    pixel.Color = "white";
+                    draw.FillColor = pixel;
+                    draw.Font = PlayedIndicatorDrawer.ExtractFont("robotoregular.ttf", _appPaths);
+                    draw.FontStyle = FontStyleType.NormalStyle;
+                    draw.TextAlignment = TextAlignType.CenterAlign;
+                    draw.FontWeight = FontWeightType.RegularStyle;
+                    draw.TextAntialias = true;
 
-                if (text.Length == 1)
-                {
-                    x += 10;
-                }
-                else if (text.Length == 2)
-                {
-                    x += 3;
-                }
-                else if (text.Length == 3)
-                {
-                    x += 1;
-                    y += 1;
-                    fontSize = 20;
-                }
+                    var fontSize = 30;
+                    var y = OffsetFromTopRightCorner + 11;
 
-                using (var font = new Font("Sans-Serif", fontSize, FontStyle.Regular, GraphicsUnit.Pixel))
-                {
-                    using (var fontBrush = new SolidBrush(Color.White))
+                    if (text.Length == 1)
+                    {
+                        x += 1;
+                    }
+                    else if (text.Length == 2)
                     {
-                        graphics.DrawString(text, font, fontBrush, x, y);
+                        x += 1;
                     }
+                    else if (text.Length >= 3)
+                    {
+                        //x += 1;
+                        y -= 2;
+                        fontSize = 24;
+                    }
+
+                    draw.FontSize = fontSize;
+                    draw.DrawAnnotation(x, y, text);
+
+                    draw.FillColor = pixel;
+                    wand.CurrentImage.DrawImage(draw);
                 }
+
             }
         }
     }
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index c49a241103..887a94ab30 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -45,8 +45,9 @@ namespace MediaBrowser.Server.Implementations.Dto
         private readonly ISyncManager _syncManager;
         private readonly IApplicationHost _appHost;
         private readonly Func<IDeviceManager> _deviceManager;
+        private readonly Func<IMediaSourceManager> _mediaSourceManager;
 
-        public DtoService(ILogger logger, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager, Func<IChannelManager> channelManagerFactory, ISyncManager syncManager, IApplicationHost appHost, Func<IDeviceManager> deviceManager)
+        public DtoService(ILogger logger, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepo, IImageProcessor imageProcessor, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager, Func<IChannelManager> channelManagerFactory, ISyncManager syncManager, IApplicationHost appHost, Func<IDeviceManager> deviceManager, Func<IMediaSourceManager> mediaSourceManager)
         {
             _logger = logger;
             _libraryManager = libraryManager;
@@ -60,6 +61,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             _syncManager = syncManager;
             _appHost = appHost;
             _deviceManager = deviceManager;
+            _mediaSourceManager = mediaSourceManager;
         }
 
         /// <summary>
@@ -159,7 +161,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             var result = _syncManager.GetLibraryItemIds(new SyncJobItemQuery
             {
                 TargetId = deviceId,
-                Statuses = new List<SyncJobItemStatus>
+                Statuses = new SyncJobItemStatus[]
                 {
                     SyncJobItemStatus.Converting,
                     SyncJobItemStatus.Queued,
@@ -257,7 +259,7 @@ namespace MediaBrowser.Server.Implementations.Dto
                     }
                     else
                     {
-                        dto.MediaSources = hasMediaSources.GetMediaSources(true, user).ToList();
+                        dto.MediaSources = _mediaSourceManager().GetStaticMediaSources(hasMediaSources, true, user).ToList();
                     }
                 }
             }
@@ -395,6 +397,18 @@ namespace MediaBrowser.Server.Implementations.Dto
                     }
                 }
             }
+
+            var userView = item as UserView;
+            if (userView != null)
+            {
+                dto.HasDynamicCategories = userView.ContainsDynamicCategories(user);
+            }
+
+            var collectionFolder = item as ICollectionFolder;
+            if (collectionFolder != null)
+            {
+                dto.HasDynamicCategories = false;
+            }
         }
 
         private int GetChildCount(Folder folder, User user)
@@ -490,7 +504,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             dto.Album = item.Album;
-            dto.Artists = item.Artists;
         }
 
         private void SetGameProperties(BaseItemDto dto, Game item)
@@ -911,7 +924,8 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Prevent implicitly captured closure
             var currentItem = item;
-            foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type)))
+            foreach (var image in currentItem.ImageInfos.Where(i => !currentItem.AllowsMultipleImages(i.Type))
+                .ToList())
             {
                 if (options.GetImageLimit(image.Type) > 0)
                 {
@@ -1127,7 +1141,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             if (audio != null)
             {
                 dto.Album = audio.Album;
-                dto.Artists = audio.Artists;
 
                 var albumParent = audio.FindParent<MusicAlbum>();
 
@@ -1148,18 +1161,65 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             if (album != null)
             {
-                dto.Artists = album.Artists;
-
                 dto.SoundtrackIds = album.SoundtrackIds
                     .Select(i => i.ToString("N"))
                     .ToArray();
             }
 
-            var hasAlbumArtist = item as IHasAlbumArtist;
+            var hasArtist = item as IHasArtist;
+            if (hasArtist != null)
+            {
+                dto.Artists = hasArtist.Artists;
 
+                dto.ArtistItems = hasArtist
+                    .Artists
+                    .Select(i =>
+                    {
+                        try
+                        {
+                            var artist = _libraryManager.GetArtist(i);
+                            return new NameIdPair
+                            {
+                                Name = artist.Name,
+                                Id = artist.Id.ToString("N")
+                            };
+                        }
+                        catch (Exception ex)
+                        {
+                            _logger.ErrorException("Error getting artist", ex);
+                            return null;
+                        }
+                    })
+                    .Where(i => i != null)
+                    .ToList();
+            }
+
+            var hasAlbumArtist = item as IHasAlbumArtist;
             if (hasAlbumArtist != null)
             {
                 dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
+
+                dto.AlbumArtists = hasAlbumArtist
+                    .AlbumArtists
+                    .Select(i =>
+                    {
+                        try
+                        {
+                            var artist = _libraryManager.GetArtist(i);
+                            return new NameIdPair
+                            {
+                                Name = artist.Name,
+                                Id = artist.Id.ToString("N")
+                            };
+                        }
+                        catch (Exception ex)
+                        {
+                            _logger.ErrorException("Error getting album artist", ex);
+                            return null;
+                        }
+                    })
+                    .Where(i => i != null)
+                    .ToList();
             }
 
             // Add video info
@@ -1216,7 +1276,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add MovieInfo
             var movie = item as Movie;
-
             if (movie != null)
             {
                 if (fields.Contains(ItemFields.TmdbCollectionName))
@@ -1226,7 +1285,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             var hasSpecialFeatures = item as IHasSpecialFeatures;
-
             if (hasSpecialFeatures != null)
             {
                 var specialFeatureCount = hasSpecialFeatures.SpecialFeatureIds.Count;
@@ -1239,7 +1297,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add EpisodeInfo
             var episode = item as Episode;
-
             if (episode != null)
             {
                 dto.IndexNumberEnd = episode.IndexNumberEnd;
@@ -1281,7 +1338,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add SeriesInfo
             var series = item as Series;
-
             if (series != null)
             {
                 dto.AirDays = series.AirDays;
@@ -1331,7 +1387,6 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             // Add SeasonInfo
             var season = item as Season;
-
             if (season != null)
             {
                 series = season.Series;
@@ -1365,7 +1420,6 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
 
             var musicVideo = item as MusicVideo;
-
             if (musicVideo != null)
             {
                 SetMusicVideoProperties(dto, musicVideo);
@@ -1597,14 +1651,11 @@ namespace MediaBrowser.Server.Implementations.Dto
 
             var path = imageInfo.Path;
 
-            // See if we can avoid a file system lookup by looking for the file in ResolveArgs
-            var dateModified = imageInfo.DateModified;
-
             ImageSize size;
 
             try
             {
-                size = _imageProcessor.GetImageSize(path, dateModified);
+                size = _imageProcessor.GetImageSize(imageInfo);
             }
             catch (FileNotFoundException)
             {
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs
index 0b06613219..28883e9a21 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs
@@ -86,6 +86,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             _userManager.UserPasswordChanged += _userManager_UserPasswordChanged;
             _userManager.UserDeleted += _userManager_UserDeleted;
             _userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated;
+            _userManager.UserLockedOut += _userManager_UserLockedOut;
 
             //_config.ConfigurationUpdated += _config_ConfigurationUpdated;
             //_config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
@@ -95,6 +96,16 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             _appHost.ApplicationUpdated += _appHost_ApplicationUpdated;
         }
 
+        void _userManager_UserLockedOut(object sender, GenericEventArgs<User> e)
+        {
+            CreateLogEntry(new ActivityLogEntry
+            {
+                Name = string.Format(_localization.GetLocalizedString("UserLockedOutWithName"), e.Argument.Name),
+                Type = "UserLockedOut",
+                UserId = e.Argument.Id.ToString("N")
+            });
+        }
+
         void _subManager_SubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
         {
             CreateLogEntry(new ActivityLogEntry
@@ -482,6 +493,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             _userManager.UserPasswordChanged -= _userManager_UserPasswordChanged;
             _userManager.UserDeleted -= _userManager_UserDeleted;
             _userManager.UserConfigurationUpdated -= _userManager_UserConfigurationUpdated;
+            _userManager.UserLockedOut -= _userManager_UserLockedOut;
 
             _config.ConfigurationUpdated -= _config_ConfigurationUpdated;
             _config.NamedConfigurationUpdated -= _config_NamedConfigurationUpdated;
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
index 37bca4ddbc..f6a35973b7 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs
@@ -78,6 +78,22 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
             _appHost.HasUpdateAvailableChanged += _appHost_HasUpdateAvailableChanged;
             _appHost.ApplicationUpdated += _appHost_ApplicationUpdated;
             _deviceManager.CameraImageUploaded +=_deviceManager_CameraImageUploaded;
+
+            _userManager.UserLockedOut += _userManager_UserLockedOut;    
+        }
+
+        async void _userManager_UserLockedOut(object sender, GenericEventArgs<User> e)
+        {
+            var type = NotificationType.UserLockedOut.ToString();
+
+            var notification = new NotificationRequest
+            {
+                NotificationType = type
+            };
+
+            notification.Variables["UserName"] = e.Argument.Name;
+
+            await SendNotification(notification).ConfigureAwait(false);
         }
 
         async void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs<CameraImageUploadInfo> e)
@@ -235,7 +251,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
                 return;
             }
 
-
             var notification = new NotificationRequest
             {
                 NotificationType = type
@@ -471,6 +486,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
             _appHost.ApplicationUpdated -= _appHost_ApplicationUpdated;
 
             _deviceManager.CameraImageUploaded -= _deviceManager_CameraImageUploaded;
+            _userManager.UserLockedOut -= _userManager_UserLockedOut;
         }
 
         private void DisposeLibraryUpdateTimer()
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 4727e6035b..f910542063 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -35,6 +35,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         private readonly ContainerAdapter _containerAdapter;
 
         public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
+        public event EventHandler<WebSocketConnectingEventArgs> WebSocketConnecting;
 
         private readonly List<string> _localEndpoints = new List<string>();
 
@@ -196,7 +197,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 
             _listener = GetListener();
 
-            _listener.WebSocketHandler = WebSocketHandler;
+            _listener.WebSocketConnected = OnWebSocketConnected;
+            _listener.WebSocketConnecting = OnWebSocketConnecting;
             _listener.ErrorHandler = ErrorHandler;
             _listener.RequestHandler = RequestHandler;
 
@@ -208,7 +210,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
             return new WebSocketSharpListener(_logger, OnRequestReceived, CertificatePath);
         }
 
-        private void WebSocketHandler(WebSocketConnectEventArgs args)
+        private void OnWebSocketConnecting(WebSocketConnectingEventArgs args)
+        {
+            if (WebSocketConnecting != null)
+            {
+                WebSocketConnecting(this, args);
+            }
+        }
+
+        private void OnWebSocketConnected(WebSocketConnectEventArgs args)
         {
             if (WebSocketConnected != null)
             {
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index 681d3ac5e5..ecf58e4a67 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -461,10 +461,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
                 {
                     return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest)
                     {
-                        Throttle = options.Throttle,
-                        ThrottleLimit = options.ThrottleLimit,
-                        MinThrottlePosition = options.MinThrottlePosition,
-                        ThrottleCallback = options.ThrottleCallback,
                         OnComplete = options.OnComplete
                     };
                 }
@@ -480,10 +476,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 
                 return new StreamWriter(stream, contentType, _logger)
                 {
-                    Throttle = options.Throttle,
-                    ThrottleLimit = options.ThrottleLimit,
-                    MinThrottlePosition = options.MinThrottlePosition,
-                    ThrottleCallback = options.ThrottleCallback,
                     OnComplete = options.OnComplete
                 };
             }
diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
index e77600e938..dc315601f2 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
@@ -24,8 +24,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         /// Gets or sets the web socket handler.
         /// </summary>
         /// <value>The web socket handler.</value>
-        Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; }
+        Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
 
+        /// <summary>
+        /// Gets or sets the web socket connecting.
+        /// </summary>
+        /// <value>The web socket connecting.</value>
+        Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
+        
         /// <summary>
         /// Starts this instance.
         /// </summary>
diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
index cdd4c6d7ca..8c72f9e7e6 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -24,10 +24,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         private long RangeLength { get; set; }
         private long TotalContentLength { get; set; }
 
-        public bool Throttle { get; set; }
-        public long ThrottleLimit { get; set; }
-        public long MinThrottlePosition;
-        public Func<long, long, long> ThrottleCallback { get; set; }
         public Action OnComplete { get; set; }
 
         /// <summary>
@@ -165,14 +161,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         /// <param name="responseStream">The response stream.</param>
         public void WriteTo(Stream responseStream)
         {
-            if (Throttle)
-            {
-                responseStream = new ThrottledStream(responseStream, ThrottleLimit)
-                {
-                    MinThrottlePosition = MinThrottlePosition,
-                    ThrottleCallback = ThrottleCallback
-                };
-            }
             WriteToInternal(responseStream);
         }
 
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs
index 9d1ddb7fc4..1bbe9893b8 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/SessionContext.cs
@@ -1,8 +1,10 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Security;
 using MediaBrowser.Controller.Session;
 using ServiceStack.Web;
+using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.HttpServer.Security
 {
@@ -19,27 +21,41 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
             _sessionManager = sessionManager;
         }
 
-        public SessionInfo GetSession(IServiceRequest requestContext)
+        public Task<SessionInfo> GetSession(IServiceRequest requestContext)
         {
             var authorization = _authContext.GetAuthorizationInfo(requestContext);
 
-            return _sessionManager.GetSession(authorization.DeviceId, authorization.Client, authorization.Version);
+            if (!string.IsNullOrWhiteSpace(authorization.Token))
+            {
+                var auth = GetTokenInfo(requestContext);
+                return _sessionManager.GetSessionByAuthenticationToken(auth, authorization.DeviceId, requestContext.RemoteIp, authorization.Version);
+            }
+
+            var session = _sessionManager.GetSession(authorization.DeviceId, authorization.Client, authorization.Version);
+            return Task.FromResult(session);
         }
 
-        public User GetUser(IServiceRequest requestContext)
+        private AuthenticationInfo GetTokenInfo(IServiceRequest request)
         {
-            var session = GetSession(requestContext);
-
-            return session == null || !session.UserId.HasValue ? null : _userManager.GetUserById(session.UserId.Value);
+            object info;
+            request.Items.TryGetValue("OriginalAuthenticationInfo", out info);
+            return info as AuthenticationInfo;
         }
 
-        public SessionInfo GetSession(object requestContext)
+        public Task<SessionInfo> GetSession(object requestContext)
         {
             var req = new ServiceStackServiceRequest((IRequest)requestContext);
             return GetSession(req);
         }
 
-        public User GetUser(object requestContext)
+        public async Task<User> GetUser(IServiceRequest requestContext)
+        {
+            var session = await GetSession(requestContext).ConfigureAwait(false);
+
+            return session == null || !session.UserId.HasValue ? null : _userManager.GetUserById(session.UserId.Value);
+        }
+
+        public Task<User> GetUser(object requestContext)
         {
             var req = new ServiceStackServiceRequest((IRequest)requestContext);
             return GetUser(req);
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
index 9dcb679f4d..8ab8b02151 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/SharpWebSocket.cs
@@ -2,6 +2,7 @@
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Logging;
 using System;
+using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 using WebSocketState = MediaBrowser.Model.Net.WebSocketState;
@@ -65,7 +66,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
 
         void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e)
         {
-            if (OnReceive != null)
+            //if (!string.IsNullOrWhiteSpace(e.Data))
+            //{
+            //    if (OnReceive != null)
+            //    {
+            //        OnReceive(e.Data);
+            //    }
+            //    return;
+            //}
+            if (OnReceiveBytes != null)
             {
                 OnReceiveBytes(e.RawData);
             }
@@ -141,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
                 WebSocket.OnMessage -= socket_OnMessage;
                 WebSocket.OnClose -= socket_OnClose;
                 WebSocket.OnError -= socket_OnError;
-                
+
                 _cancellationTokenSource.Cancel();
 
                 WebSocket.Close();
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index 0c5c9e9bf1..fdb27d40db 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Net;
+using System.Collections.Specialized;
+using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Server.Implementations.Logging;
 using ServiceStack;
@@ -18,9 +19,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
 
         private readonly ILogger _logger;
         private readonly Action<string> _endpointListener;
-        private readonly string  _certificatePath ;
+        private readonly string _certificatePath;
 
-        public WebSocketSharpListener(ILogger logger, Action<string> endpointListener, 
+        public WebSocketSharpListener(ILogger logger, Action<string> endpointListener,
             string certificatePath)
         {
             _logger = logger;
@@ -32,7 +33,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
 
         public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
 
-        public Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; }
+        public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
+
+        public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
 
         public void Start(IEnumerable<string> urlPrefixes)
         {
@@ -115,15 +118,44 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
         {
             try
             {
-                var webSocketContext = ctx.AcceptWebSocket(null);
+                var endpoint = ctx.Request.RemoteEndPoint.ToString();
+                var url = ctx.Request.RawUrl;
+                var queryString = new NameValueCollection(ctx.Request.QueryString ?? new NameValueCollection());
+
+                var connectingArgs = new WebSocketConnectingEventArgs
+                {
+                    Url = url,
+                    QueryString = queryString,
+                    Endpoint = endpoint
+                };
+
+                if (WebSocketConnecting != null)
+                {
+                    WebSocketConnecting(connectingArgs);
+                }
 
-                if (WebSocketHandler != null)
+                if (connectingArgs.AllowConnection)
                 {
-                    WebSocketHandler(new WebSocketConnectEventArgs
+                    _logger.Debug("Web socket connection allowed");
+
+                    var webSocketContext = ctx.AcceptWebSocket(null);
+
+                    if (WebSocketConnected != null)
                     {
-                        WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger),
-                        Endpoint = ctx.Request.RemoteEndPoint.ToString()
-                    });
+                        WebSocketConnected(new WebSocketConnectEventArgs
+                        {
+                            Url = url,
+                            QueryString = queryString,
+                            WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger),
+                            Endpoint = endpoint
+                        });
+                    }
+                }
+                else
+                {
+                    _logger.Warn("Web socket connection not allowed");
+                    ctx.Response.StatusCode = 401;
+                    ctx.Response.Close();
                 }
             }
             catch (Exception ex)
diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
index 1db14e8878..fe662542ef 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
@@ -35,10 +35,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
             get { return _options; }
         }
 
-        public bool Throttle { get; set; }
-        public long ThrottleLimit { get; set; }
-        public long MinThrottlePosition;
-        public Func<long, long, long> ThrottleCallback { get; set; }
         public Action OnComplete { get; set; }
 
         /// <summary>
@@ -82,14 +78,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         /// <param name="responseStream">The response stream.</param>
         public void WriteTo(Stream responseStream)
         {
-            if (Throttle)
-            {
-                responseStream = new ThrottledStream(responseStream, ThrottleLimit)
-                {
-                    MinThrottlePosition = MinThrottlePosition,
-                    ThrottleCallback = ThrottleCallback
-                };
-            }
             WriteToInternal(responseStream);
         }
 
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index e6e6b8c74b..1f82e7ef13 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -1584,15 +1584,22 @@ namespace MediaBrowser.Server.Implementations.Library
                 .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
         }
 
-        public async Task<UserView> GetNamedView(string name,
-            string type,
+        public async Task<UserView> GetNamedView(User user,
+            string name,
+            string viewType,
             string sortName,
             CancellationToken cancellationToken)
         {
+            if (ConfigurationManager.Configuration.EnableUserSpecificUserViews)
+            {
+                return await GetNamedViewInternal(user, name, null, viewType, sortName, cancellationToken)
+                            .ConfigureAwait(false);
+            }
+
             var path = Path.Combine(ConfigurationManager.ApplicationPaths.ItemsByNamePath,
                             "views");
 
-            path = Path.Combine(path, _fileSystem.GetValidFilename(type));
+            path = Path.Combine(path, _fileSystem.GetValidFilename(viewType));
 
             var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView));
 
@@ -1611,7 +1618,7 @@ namespace MediaBrowser.Server.Implementations.Library
                     Id = id,
                     DateCreated = DateTime.UtcNow,
                     Name = name,
-                    ViewType = type,
+                    ViewType = viewType,
                     ForcedSortName = sortName
                 };
 
@@ -1627,31 +1634,38 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (refresh)
             {
-                await item.RefreshMetadata(new MetadataRefreshOptions
-                {
-                    ForceSave = true
-
-                }, cancellationToken).ConfigureAwait(false);
+                await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
+                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
             }
 
             return item;
         }
 
-        public async Task<UserView> GetSpecialFolder(User user,
+        public Task<UserView> GetNamedView(User user,
             string name,
             string parentId,
             string viewType,
             string sortName,
             CancellationToken cancellationToken)
         {
-            if (string.IsNullOrWhiteSpace(name))
+            if (string.IsNullOrWhiteSpace(parentId))
             {
-                throw new ArgumentNullException("name");
+                throw new ArgumentNullException("parentId");
             }
 
-            if (string.IsNullOrWhiteSpace(parentId))
+            return GetNamedViewInternal(user, name, parentId, viewType, sortName, cancellationToken);
+        }
+
+        private async Task<UserView> GetNamedViewInternal(User user,
+            string name,
+            string parentId,
+            string viewType,
+            string sortName,
+            CancellationToken cancellationToken)
+        {
+            if (string.IsNullOrWhiteSpace(name))
             {
-                throw new ArgumentNullException("parentId");
+                throw new ArgumentNullException("name");
             }
 
             if (string.IsNullOrWhiteSpace(viewType))
@@ -1659,13 +1673,13 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("viewType");
             }
 
-            var id = GetNewItemId("7_namedview_" + name + user.Id.ToString("N") + parentId, typeof(UserView));
+            var id = GetNewItemId("37_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView));
 
-            var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", "specialviews", id.ToString("N"));
+            var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
 
             var item = GetItemById(id) as UserView;
 
-            var refresh = false;
+            var isNew = false;
 
             if (item == null)
             {
@@ -1679,27 +1693,24 @@ namespace MediaBrowser.Server.Implementations.Library
                     Name = name,
                     ViewType = viewType,
                     ForcedSortName = sortName,
-                    UserId = user.Id,
-                    ParentId = new Guid(parentId)
+                    UserId = user.Id
                 };
 
+                if (!string.IsNullOrWhiteSpace(parentId))
+                {
+                    item.ParentId = new Guid(parentId);
+                }
+
                 await CreateItem(item, cancellationToken).ConfigureAwait(false);
 
-                refresh = true;
+                isNew = true;
             }
 
-            if (!refresh && item != null)
-            {
-                refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
-            }
+            var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 6;
 
             if (refresh)
             {
-                await item.RefreshMetadata(new MetadataRefreshOptions
-                {
-                    ForceSave = true
-
-                }, cancellationToken).ConfigureAwait(false);
+                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
             }
 
             return item;
@@ -1846,6 +1857,10 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             var options = new ExtendedNamingOptions();
 
+            // These cause apps to have problems
+            options.AudioFileExtensions.Remove(".m3u");
+            options.AudioFileExtensions.Remove(".wpl");
+
             if (!ConfigurationManager.Configuration.EnableAudioArchiveFiles)
             {
                 options.AudioFileExtensions.Remove(".rar");
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index a45757d135..2880c9e16e 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -1,18 +1,43 @@
-using MediaBrowser.Controller.Library;
+using System.IO;
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Model.MediaInfo;
 
 namespace MediaBrowser.Server.Implementations.Library
 {
     public class MediaSourceManager : IMediaSourceManager
     {
         private readonly IItemRepository _itemRepo;
+        private readonly IUserManager _userManager;
+        private readonly ILibraryManager _libraryManager;
+        private readonly IChannelManager _channelManager;
 
-        public MediaSourceManager(IItemRepository itemRepo)
+        private IMediaSourceProvider[] _providers;
+        private readonly ILogger _logger;
+
+        public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, IChannelManager channelManager, ILogger logger)
         {
             _itemRepo = itemRepo;
+            _userManager = userManager;
+            _libraryManager = libraryManager;
+            _channelManager = channelManager;
+            _logger = logger;
+        }
+
+        public void AddParts(IEnumerable<IMediaSourceProvider> providers)
+        {
+            _providers = providers.ToArray();
         }
 
         public IEnumerable<MediaStream> GetMediaStreams(MediaStreamQuery query)
@@ -47,5 +72,223 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             return true;
         }
+
+        public IEnumerable<MediaStream> GetMediaStreams(string mediaSourceId)
+        {
+            var list = GetMediaStreams(new MediaStreamQuery
+            {
+                ItemId = new Guid(mediaSourceId)
+            });
+
+            return GetMediaStreamsForItem(list);
+        }
+
+        public IEnumerable<MediaStream> GetMediaStreams(Guid itemId)
+        {
+            var list = GetMediaStreams(new MediaStreamQuery
+            {
+                ItemId = itemId
+            });
+
+            return GetMediaStreamsForItem(list);
+        }
+
+        private IEnumerable<MediaStream> GetMediaStreamsForItem(IEnumerable<MediaStream> streams)
+        {
+            var list = streams.ToList();
+
+            var subtitleStreams = list
+                .Where(i => i.Type == MediaStreamType.Subtitle)
+                .ToList();
+
+            if (subtitleStreams.Count > 0)
+            {
+                var videoStream = list.FirstOrDefault(i => i.Type == MediaStreamType.Video);
+
+                // This is abitrary but at some point it becomes too slow to extract subtitles on the fly
+                // We need to learn more about when this is the case vs. when it isn't
+                const int maxAllowedBitrateForExternalSubtitleStream = 10000000;
+
+                var videoBitrate = videoStream == null ? maxAllowedBitrateForExternalSubtitleStream : videoStream.BitRate ?? maxAllowedBitrateForExternalSubtitleStream;
+
+                foreach (var subStream in subtitleStreams)
+                {
+                    var supportsExternalStream = StreamSupportsExternalStream(subStream);
+
+                    if (supportsExternalStream && videoBitrate >= maxAllowedBitrateForExternalSubtitleStream)
+                    {
+                        supportsExternalStream = false;
+                    }
+
+                    subStream.SupportsExternalStream = supportsExternalStream;
+                }
+            }
+
+            return list;
+        }
+
+        public async Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken)
+        {
+            var item = _libraryManager.GetItemById(id);
+            IEnumerable<MediaSourceInfo> mediaSources;
+
+            var hasMediaSources = (IHasMediaSources)item;
+            var channelItem = item as IChannelMediaItem;
+
+            if (channelItem != null)
+            {
+                mediaSources = await _channelManager.GetChannelItemMediaSources(id, true, cancellationToken)
+                        .ConfigureAwait(false);
+            }
+            else
+            {
+                if (string.IsNullOrWhiteSpace(userId))
+                {
+                    mediaSources = hasMediaSources.GetMediaSources(enablePathSubstitution);
+                }
+                else
+                {
+                    var user = _userManager.GetUserById(userId);
+                    mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
+                }
+            }
+
+            var dynamicMediaSources = await GetDynamicMediaSources(hasMediaSources, cancellationToken).ConfigureAwait(false);
+
+            var list = new List<MediaSourceInfo>();
+
+            list.AddRange(mediaSources);
+
+            foreach (var source in dynamicMediaSources)
+            {
+                source.SupportsTranscoding = false;
+
+                if (source.Protocol == MediaProtocol.File)
+                {
+                    source.SupportsDirectStream = File.Exists(source.Path);
+                }
+
+                list.Add(source);
+            }
+
+            return SortMediaSources(list);
+        }
+
+        private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
+        {
+            var tasks = _providers.Select(i => GetDynamicMediaSources(item, i, cancellationToken));
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+
+            return results.SelectMany(i => i.ToList());
+        }
+
+        private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, IMediaSourceProvider provider, CancellationToken cancellationToken)
+        {
+            try
+            {
+                return await provider.GetMediaSources(item, cancellationToken).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error getting media sources", ex);
+                return new List<MediaSourceInfo>();
+            }
+        }
+
+        public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken)
+        {
+            return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
+        }
+
+        public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+
+            if (!(item is Video))
+            {
+                return item.GetMediaSources(enablePathSubstitution);
+            }
+
+            return item.GetMediaSources(enablePathSubstitution);
+        }
+
+        public IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user)
+        {
+            if (item == null)
+            {
+                throw new ArgumentNullException("item");
+            }
+
+            if (!(item is Video))
+            {
+                return item.GetMediaSources(enablePathSubstitution);
+            }
+
+            if (user == null)
+            {
+                throw new ArgumentNullException("user");
+            }
+
+            var sources = item.GetMediaSources(enablePathSubstitution).ToList();
+
+            foreach (var source in sources)
+            {
+                SetUserProperties(source, user);
+            }
+
+            return sources;
+        }
+
+        private void SetUserProperties(MediaSourceInfo source, User user)
+        {
+            var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
+            ? new string[] { }
+            : new[] { user.Configuration.AudioLanguagePreference };
+
+            var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
+                ? new List<string> { }
+                : new List<string> { user.Configuration.SubtitleLanguagePreference };
+
+            source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
+
+            var defaultAudioIndex = source.DefaultAudioStreamIndex;
+            var audioLangage = defaultAudioIndex == null
+                ? null
+                : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
+
+            source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
+                preferredSubs,
+                user.Configuration.SubtitleMode,
+                audioLangage);
+        }
+
+        private IEnumerable<MediaSourceInfo> SortMediaSources(IEnumerable<MediaSourceInfo> sources)
+        {
+            return sources.OrderBy(i =>
+            {
+                if (i.VideoType.HasValue && i.VideoType.Value == VideoType.VideoFile)
+                {
+                    return 0;
+                }
+
+                return 1;
+
+            }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
+            .ThenByDescending(i =>
+            {
+                var stream = i.VideoStream;
+
+                return stream == null || stream.Width == null ? 0 : stream.Width.Value;
+            })
+            .ToList();
+        }
+
+        public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution)
+        {
+            return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
+        }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
index 7733e7d379..3a854f2fe0 100644
--- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Library
             var genres = user.RootFolder
                 .GetRecursiveChildren(user, i => i is Audio)
                 .Cast<Audio>()
-                .Where(i => i.HasArtist(name))
+                .Where(i => i.HasAnyArtist(name))
                 .SelectMany(i => i.Genres)
                 .Concat(artist.Genres)
                 .Distinct(StringComparer.OrdinalIgnoreCase);
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 95dcee98ad..71daf2b0cf 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -62,6 +62,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
                 return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
             }
 
+            if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
+            {
+                return ResolveVideos<Video>(parent, files, directoryService, collectionType, false);
+            }
+
             if (string.IsNullOrEmpty(collectionType))
             {
                 // Owned items should just use the plain video type
@@ -225,6 +230,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
             {
                 item = ResolveVideo<Video>(args, false);
             }
+            else if (string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
+            {
+                item = ResolveVideo<Video>(args, false);
+            }
             else if (string.IsNullOrEmpty(collectionType))
             {
                 if (args.HasParent<Series>())
@@ -358,6 +367,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
             }
 
             var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) &&
+                                    !string.Equals(collectionType, CollectionType.Photos) &&
                                     !string.Equals(collectionType, CollectionType.MusicVideos);
 
             var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, collectionType, supportsMultiVersion);
@@ -474,7 +484,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
                 CollectionType.Movies,
                 CollectionType.HomeVideos,
                 CollectionType.MusicVideos,
-                CollectionType.Movies
+                CollectionType.Movies,
+                CollectionType.Photos
             };
 
             return !validCollectionTypes.Contains(collectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
index 02960ea7ea..b714e968b5 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoResolver.cs
@@ -30,7 +30,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
             return null;
         }
 
-        protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff" };
+        // Some common file name extensions for RAW picture files include: .cr2, .crw, .dng, .nef, .orf, .rw2, .pef, .arw, .sr2, .srf, and .tif.
+        protected static string[] ImageExtensions = { ".tiff", ".jpeg", ".jpg", ".png", ".aiff", ".cr2", ".crw", ".dng", ".nef", ".orf", ".pef", ".arw", ".webp" };
 
         private static readonly string[] IgnoreFiles =
         {
diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 7371ca5a9c..3551b71b7f 100644
--- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -1,19 +1,18 @@
-using System.Collections.Generic;
-using System.Linq;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Model.Entities;
-using System;
-using System.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Naming.Common;
 using MediaBrowser.Naming.IO;
 using MediaBrowser.Naming.TV;
 using MediaBrowser.Server.Implementations.Logging;
-using EpisodeInfo = MediaBrowser.Controller.Providers.EpisodeInfo;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
 
 namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV
 {
diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs
index 59fecc857c..b101f6ae1a 100644
--- a/MediaBrowser.Server.Implementations/Library/UserManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs
@@ -97,6 +97,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// </summary>
         public event EventHandler<GenericEventArgs<User>> UserUpdated;
         public event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
+        public event EventHandler<GenericEventArgs<User>> UserLockedOut;
 
         /// <summary>
         /// Called when [user updated].
@@ -192,10 +193,10 @@ namespace MediaBrowser.Server.Implementations.Library
         public bool IsValidUsername(string username)
         {
             // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
-            return username.All(IsValidCharacter);
+            return username.All(IsValidUsernameCharacter);
         }
 
-        private bool IsValidCharacter(char i)
+        private bool IsValidUsernameCharacter(char i)
         {
             return char.IsLetterOrDigit(i) || char.Equals(i, '-') || char.Equals(i, '_') || char.Equals(i, '\'') ||
                    char.Equals(i, '.');
@@ -213,7 +214,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
             foreach (var c in username)
             {
-                if (IsValidCharacter(c))
+                if (IsValidUsernameCharacter(c))
                 {
                     builder.Append(c);
                 }
@@ -259,6 +260,11 @@ namespace MediaBrowser.Server.Implementations.Library
             {
                 user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
                 await UpdateUser(user).ConfigureAwait(false);
+                await UpdateInvalidLoginAttemptCount(user, 0).ConfigureAwait(false);
+            }
+            else
+            {
+                await UpdateInvalidLoginAttemptCount(user, user.Policy.InvalidLoginAttemptCount + 1).ConfigureAwait(false);
             }
 
             _logger.Info("Authentication request for {0} {1}.", user.Name, (success ? "has succeeded" : "has been denied"));
@@ -266,6 +272,38 @@ namespace MediaBrowser.Server.Implementations.Library
             return success;
         }
 
+        private async Task UpdateInvalidLoginAttemptCount(User user, int newValue)
+        {
+            if (user.Policy.InvalidLoginAttemptCount != newValue || newValue > 0)
+            {
+                user.Policy.InvalidLoginAttemptCount = newValue;
+
+                var maxCount = user.Policy.IsAdministrator ? 
+                    3 : 
+                    5;
+
+                var fireLockout = false;
+
+                if (newValue >= maxCount)
+                {
+                    //_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture));
+                    //user.Policy.IsDisabled = true;
+
+                    //fireLockout = true;
+                }
+
+                await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false);
+
+                if (fireLockout)
+                {
+                    if (UserLockedOut != null)
+                    {
+                        EventHelper.FireEventIfNotNull(UserLockedOut, this, new GenericEventArgs<User>(user), _logger);
+                    }
+                }
+            }
+        }
+
         private string GetPasswordHash(User user)
         {
             return string.IsNullOrEmpty(user.Password)
@@ -332,11 +370,6 @@ namespace MediaBrowser.Server.Implementations.Library
         {
             if (!user.Configuration.HasMigratedToPolicy)
             {
-                user.Policy.BlockUnratedItems = user.Configuration.BlockUnratedItems;
-                user.Policy.EnableContentDeletion = user.Configuration.EnableContentDeletion;
-                user.Policy.EnableLiveTvAccess = user.Configuration.EnableLiveTvAccess;
-                user.Policy.EnableLiveTvManagement = user.Configuration.EnableLiveTvManagement;
-                user.Policy.EnableMediaPlayback = user.Configuration.EnableMediaPlayback;
                 user.Policy.IsAdministrator = user.Configuration.IsAdministrator;
 
                 await UpdateUserPolicy(user, user.Policy, false);
@@ -815,6 +848,12 @@ namespace MediaBrowser.Server.Implementations.Library
                 foreach (var user in users)
                 {
                     await ResetPassword(user).ConfigureAwait(false);
+
+                    if (user.Policy.IsDisabled)
+                    {
+                        user.Policy.IsDisabled = false;
+                        await UpdateUserPolicy(user, user.Policy, true).ConfigureAwait(false);
+                    }
                     usersReset.Add(user.Name);
                 }
             }
@@ -915,10 +954,6 @@ namespace MediaBrowser.Server.Implementations.Library
             }
 
             user.Configuration.IsAdministrator = user.Policy.IsAdministrator;
-            user.Configuration.EnableLiveTvManagement = user.Policy.EnableLiveTvManagement;
-            user.Configuration.EnableLiveTvAccess = user.Policy.EnableLiveTvAccess;
-            user.Configuration.EnableMediaPlayback = user.Policy.EnableMediaPlayback;
-            user.Configuration.EnableContentDeletion = user.Policy.EnableContentDeletion;
 
             await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false);
         }
diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
index a8ca1a2e06..e63a275511 100644
--- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs
@@ -2,7 +2,6 @@
 using MediaBrowser.Controller.Collections;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Localization;
@@ -11,12 +10,12 @@ using MediaBrowser.Model.Channels;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Library;
 using MediaBrowser.Model.Querying;
+using MoreLinq;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MoreLinq;
 
 namespace MediaBrowser.Server.Implementations.Library
 {
@@ -53,8 +52,6 @@ namespace MediaBrowser.Server.Implementations.Library
                 .OfType<Folder>()
                 .ToList();
 
-            var list = new List<Folder>();
-
             var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
 
             var standaloneFolders = folders
@@ -66,46 +63,68 @@ namespace MediaBrowser.Server.Implementations.Library
                 .OfType<ICollectionFolder>()
                 .ToList();
 
-            list.AddRange(standaloneFolders);
+            var list = new List<Folder>();
+
+            if (_config.Configuration.EnableUserSpecificUserViews)
+            {
+                foreach (var folder in standaloneFolders)
+                {
+                    var collectionFolder = folder as ICollectionFolder;
+                    var folderViewType = collectionFolder == null ? null : collectionFolder.CollectionType;
+
+                    if (string.IsNullOrWhiteSpace(folderViewType))
+                    {
+                        list.Add(folder);
+                    }
+                    else
+                    {
+                        list.Add(await GetUserView(folder.Id, folder.Name, folderViewType, string.Empty, user, cancellationToken).ConfigureAwait(false));
+                    }
+                }
+            }
+            else
+            {
+                list.AddRange(standaloneFolders);
+            }
 
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) ||
                 foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType)))
             {
-                list.Add(await GetUserView(CollectionType.TvShows, string.Empty, cancellationToken).ConfigureAwait(false));
+                list.Add(await GetUserView(CollectionType.TvShows, string.Empty, user, cancellationToken).ConfigureAwait(false));
             }
 
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase)) ||
                 foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)))
             {
-                list.Add(await GetUserView(CollectionType.Music, string.Empty, cancellationToken).ConfigureAwait(false));
+                list.Add(await GetUserView(CollectionType.Music, string.Empty, user, cancellationToken).ConfigureAwait(false));
             }
 
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) ||
                 foldersWithViewTypes.Any(i => string.IsNullOrWhiteSpace(i.CollectionType)))
             {
-                list.Add(await GetUserView(CollectionType.Movies, string.Empty, cancellationToken).ConfigureAwait(false));
+                list.Add(await GetUserView(CollectionType.Movies, string.Empty, user, cancellationToken).ConfigureAwait(false));
             }
 
-            if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase))
-                || _config.Configuration.EnableLegacyCollectionInView)
+            if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Games, StringComparison.OrdinalIgnoreCase)))
             {
-                list.Add(await GetUserView(CollectionType.Games, string.Empty, cancellationToken).ConfigureAwait(false));
+                list.Add(await GetUserView(CollectionType.Games, string.Empty, user, cancellationToken).ConfigureAwait(false));
             }
 
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)))
             {
                 //list.Add(_collectionManager.GetCollectionsFolder(user.Id.ToString("N")));
-                list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, cancellationToken).ConfigureAwait(false));
+                list.Add(await GetUserView(CollectionType.BoxSets, string.Empty, user, cancellationToken).ConfigureAwait(false));
             }
 
             if (foldersWithViewTypes.Any(i => string.Equals(i.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)))
             {
-                list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N")));
+                //list.Add(_playlists.GetPlaylistsFolder(user.Id.ToString("N")));
+                list.Add(await GetUserView(CollectionType.Playlists, string.Empty, user, cancellationToken).ConfigureAwait(false));
             }
 
             if (user.Configuration.DisplayFoldersView)
             {
-                list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, cancellationToken).ConfigureAwait(false));
+                list.Add(await GetUserView(CollectionType.Folders, "zz_" + CollectionType.Folders, user, cancellationToken).ConfigureAwait(false));
             }
 
             if (query.IncludeExternalContent)
@@ -131,7 +150,8 @@ namespace MediaBrowser.Server.Implementations.Library
 
                 if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
                 {
-                    list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false));
+                    //list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false));
+                    list.Add(await GetUserView(CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false));
                 }
             }
 
@@ -150,23 +170,28 @@ namespace MediaBrowser.Server.Implementations.Library
                 .ThenBy(i => i.SortName);
         }
 
-        public Task<UserView> GetUserView(string name, string parentId, string type, User user, string sortName, CancellationToken cancellationToken)
+        public Task<UserView> GetUserSubView(string name, string parentId, string type, User user, string sortName, CancellationToken cancellationToken)
         {
-            return _libraryManager.GetSpecialFolder(user, name, parentId, type, sortName, cancellationToken);
+            return _libraryManager.GetNamedView(user, name, parentId, type, sortName, cancellationToken);
         }
 
-        public Task<UserView> GetUserView(string parentId, string type, User user, string sortName, CancellationToken cancellationToken)
+        public Task<UserView> GetUserSubView(string parentId, string type, User user, string sortName, CancellationToken cancellationToken)
         {
             var name = _localizationManager.GetLocalizedString("ViewType" + type);
 
-            return GetUserView(name, parentId, type, user, sortName, cancellationToken);
+            return GetUserSubView(name, parentId, type, user, sortName, cancellationToken);
         }
 
-        public Task<UserView> GetUserView(string type, string sortName, CancellationToken cancellationToken)
+        public Task<UserView> GetUserView(string type, string sortName, User user, CancellationToken cancellationToken)
         {
             var name = _localizationManager.GetLocalizedString("ViewType" + type);
 
-            return _libraryManager.GetNamedView(name, type, sortName, cancellationToken);
+            return _libraryManager.GetNamedView(user, name, type, sortName, cancellationToken);
+        }
+
+        public Task<UserView> GetUserView(Guid parentId, string name, string type, string sortName, User user, CancellationToken cancellationToken)
+        {
+            return _libraryManager.GetNamedView(user, name, parentId.ToString("N"), type, sortName, cancellationToken);
         }
 
         public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request)
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
index f1bb5c13ae..7f4440fbce 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs
@@ -387,7 +387,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 IsPremiere = item.IsPremiere,
                 Type = "Program",
                 MediaType = item.MediaType,
-                ServerId = _appHost.SystemId
+                ServerId = _appHost.SystemId,
+                ProductionYear = item.ProductionYear
             };
 
             if (item.EndDate.HasValue)
@@ -442,7 +443,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return null;
         }
 
-        private const string InternalVersionNumber = "3";
+        private const string InternalVersionNumber = "4";
 
         public Guid GetInternalChannelId(string serviceName, string externalId)
         {
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index be3926f4c1..777a8936b9 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1,7 +1,6 @@
 using MediaBrowser.Common;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Channels;
@@ -24,7 +23,6 @@ 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;
@@ -37,7 +35,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
     public class LiveTvManager : ILiveTvManager, IDisposable
     {
         private readonly IServerConfigurationManager _config;
-        private readonly IFileSystem _fileSystem;
         private readonly ILogger _logger;
         private readonly IItemRepository _itemRepo;
         private readonly IUserManager _userManager;
@@ -45,6 +42,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         private readonly ILibraryManager _libraryManager;
         private readonly ITaskManager _taskManager;
         private readonly IJsonSerializer _jsonSerializer;
+        private readonly IProviderManager _providerManager;
 
         private readonly IDtoService _dtoService;
         private readonly ILocalizationManager _localization;
@@ -62,10 +60,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
 
-        public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer)
+        public LiveTvManager(IApplicationHost appHost, IServerConfigurationManager config, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, IProviderManager providerManager)
         {
             _config = config;
-            _fileSystem = fileSystem;
             _logger = logger;
             _itemRepo = itemRepo;
             _userManager = userManager;
@@ -73,6 +70,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             _taskManager = taskManager;
             _localization = localization;
             _jsonSerializer = jsonSerializer;
+            _providerManager = providerManager;
             _dtoService = dtoService;
             _userDataManager = userDataManager;
 
@@ -103,27 +101,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             _services.AddRange(services);
 
-            SetActiveService(GetConfiguration().ActiveService);
-        }
-
-        private void SetActiveService(string name)
-        {
-            var service = _services.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase)) ??
-                _services.FirstOrDefault();
-
-            SetActiveService(service);
-        }
-
-        private void SetActiveService(ILiveTvService service)
-        {
-            if (ActiveService != null)
-            {
-                ActiveService.DataSourceChanged -= service_DataSourceChanged;
-            }
-
-            ActiveService = service;
+            ActiveService = _services.FirstOrDefault();
 
-            if (service != null)
+            foreach (var service in _services)
             {
                 service.DataSourceChanged += service_DataSourceChanged;
             }
@@ -255,7 +235,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             foreach (var channel in internalResult.Items)
             {
-                var currentProgram = await GetCurrentProgram(channel.ExternalId, cancellationToken).ConfigureAwait(false);
+                var currentProgram = GetCurrentProgram(channel.ExternalId);
 
                 returnList.Add(_tvDtoService.GetChannelInfoDto(channel, currentProgram, user));
             }
@@ -279,7 +259,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return _libraryManager.GetItemById(id) as LiveTvChannel;
         }
 
-        public async Task<LiveTvProgram> GetInternalProgram(string id, CancellationToken cancellationToken)
+        private LiveTvProgram GetInternalProgram(string id)
         {
             var guid = new Guid(id);
 
@@ -289,48 +269,37 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             if (obj != null)
             {
-                await RefreshIfNeeded(obj, cancellationToken).ConfigureAwait(false);
+                RefreshIfNeeded(obj);
             }
             return obj;
         }
 
-        private Task RefreshIfNeeded(IEnumerable<LiveTvProgram> programs, CancellationToken cancellationToken)
+        private void RefreshIfNeeded(LiveTvProgram program)
         {
-            var list = programs.ToList();
-
-            Task.Run(async () =>
+            if (!_refreshedPrograms.ContainsKey(program.Id))
             {
-                foreach (var program in list)
-                {
-                    await RefreshIfNeeded(program, CancellationToken.None).ConfigureAwait(false);
-                }
-
-            }, cancellationToken);
-
-            return Task.FromResult(true);
+                _refreshedPrograms.TryAdd(program.Id, true);
+                _providerManager.QueueRefresh(program.Id, new MetadataRefreshOptions());
+            }
         }
 
-        private readonly Task _cachedTask = Task.FromResult(true);
-        private Task RefreshIfNeeded(LiveTvProgram program, CancellationToken cancellationToken)
+        private void RefreshIfNeeded(IEnumerable<LiveTvProgram> programs)
         {
-            if (!_refreshedPrograms.ContainsKey(program.Id))
+            foreach (var program in programs)
             {
-                _refreshedPrograms.TryAdd(program.Id, true);
-                return program.RefreshMetadata(cancellationToken);
+                RefreshIfNeeded(program);
             }
-
-            return _cachedTask;
         }
 
         public async Task<ILiveTvRecording> GetInternalRecording(string id, CancellationToken cancellationToken)
         {
-            var service = ActiveService;
-
-            var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
+            var result = await GetInternalRecordings(new RecordingQuery
+            {
+                Id = id
 
-            var recording = recordings.FirstOrDefault(i => _tvDtoService.GetInternalRecordingId(service.Name, i.Id) == new Guid(id));
+            }, cancellationToken).ConfigureAwait(false);
 
-            return await GetRecording(recording, service.Name, cancellationToken).ConfigureAwait(false);
+            return result.Items.FirstOrDefault() as ILiveTvRecording;
         }
 
         private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
@@ -345,29 +314,38 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return await GetLiveStream(id, true, cancellationToken).ConfigureAwait(false);
         }
 
+        private ILiveTvService GetService(ILiveTvItem item)
+        {
+            return GetService(item.ServiceName);
+        }
+
+        private ILiveTvService GetService(string name)
+        {
+            return _services.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
+        }
+
         private async Task<ChannelMediaInfo> GetLiveStream(string id, bool isChannel, CancellationToken cancellationToken)
         {
             await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
 
             try
             {
-                var service = ActiveService;
                 ChannelMediaInfo info;
 
                 if (isChannel)
                 {
                     var channel = GetInternalChannel(id);
+                    var service = GetService(channel);
                     _logger.Info("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId);
-
                     info = await service.GetChannelStream(channel.ExternalId, cancellationToken).ConfigureAwait(false);
                 }
                 else
                 {
-                    var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
-                    var recording = recordings.First(i => _tvDtoService.GetInternalRecordingId(service.Name, i.Id) == new Guid(id));
+                    var recording = await GetInternalRecording(id, cancellationToken).ConfigureAwait(false);
+                    var service = GetService(recording);
 
-                    _logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.Id);
-                    info = await service.GetRecordingStream(recording.Id, cancellationToken).ConfigureAwait(false);
+                    _logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.RecordingInfo.Id);
+                    info = await service.GetRecordingStream(recording.RecordingInfo.Id, cancellationToken).ConfigureAwait(false);
                 }
 
                 _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
@@ -492,11 +470,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return item;
         }
 
-        private LiveTvProgram GetProgram(ProgramInfo info, ChannelType channelType, string serviceName, CancellationToken cancellationToken)
+        private async Task<LiveTvProgram> GetProgram(ProgramInfo info, ChannelType channelType, string serviceName, CancellationToken cancellationToken)
         {
             var id = _tvDtoService.GetInternalProgramId(serviceName, info.Id);
 
-            var item = _itemRepo.RetrieveItem(id) as LiveTvProgram;
+            var item = _libraryManager.GetItemById(id) as LiveTvProgram;
 
             if (item == null)
             {
@@ -537,6 +515,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             item.ProviderImageUrl = info.ImageUrl;
             item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks;
             item.StartDate = info.StartDate;
+            item.ProductionYear = info.ProductionYear;
+
+            await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
 
             return item;
         }
@@ -616,7 +597,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task<ProgramInfoDto> GetProgram(string id, CancellationToken cancellationToken, User user = null)
         {
-            var program = await GetInternalProgram(id, cancellationToken).ConfigureAwait(false);
+            var program = GetInternalProgram(id);
 
             var channel = GetChannel(program);
 
@@ -659,23 +640,28 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 programs = programs.Where(i => i.StartDate <= val);
             }
 
-            if (query.ChannelIdList.Length > 0)
+            if (query.HasAired.HasValue)
             {
-                var guids = query.ChannelIdList.Select(i => new Guid(i)).ToList();
-                var serviceName = ActiveService.Name;
+                var val = query.HasAired.Value;
+                programs = programs.Where(i => i.HasAired == val);
+            }
+
+            if (query.ChannelIds.Length > 0)
+            {
+                var guids = query.ChannelIds.Select(i => new Guid(i)).ToList();
 
                 programs = programs.Where(i =>
                 {
                     var programChannelId = i.ExternalChannelId;
 
-                    var internalProgramChannelId = _tvDtoService.GetInternalChannelId(serviceName, programChannelId);
+                    var service = GetService(i);
+                    var internalProgramChannelId = _tvDtoService.GetInternalChannelId(service.Name, programChannelId);
 
                     return guids.Contains(internalProgramChannelId);
                 });
             }
 
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
-
             if (user != null)
             {
                 // Avoid implicitly captured closure
@@ -683,9 +669,34 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 programs = programs.Where(i => i.IsVisible(currentUser));
             }
 
+            // Apply genre filter
+            if (query.Genres.Length > 0)
+            {
+                programs = programs.Where(p => p.Genres.Any(g => query.Genres.Contains(g, StringComparer.OrdinalIgnoreCase)));
+            }
+
+            if (query.IsMovie.HasValue)
+            {
+                programs = programs.Where(p => p.IsMovie == query.IsMovie);
+            }
+
+            programs = _libraryManager.Sort(programs, user, query.SortBy, query.SortOrder ?? SortOrder.Ascending)
+                .Cast<LiveTvProgram>();
+
             var programList = programs.ToList();
+            IEnumerable<LiveTvProgram> returnPrograms = programList;
+
+            if (query.StartIndex.HasValue)
+            {
+                returnPrograms = returnPrograms.Skip(query.StartIndex.Value);
+            }
 
-            var returnArray = programList
+            if (query.Limit.HasValue)
+            {
+                returnPrograms = returnPrograms.Take(query.Limit.Value);
+            }
+
+            var returnArray = returnPrograms
                 .Select(i =>
                 {
                     var channel = GetChannel(i);
@@ -694,14 +705,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 })
                 .ToArray();
 
-            await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false);
+            RefreshIfNeeded(programList);
 
             await AddRecordingInfo(returnArray, cancellationToken).ConfigureAwait(false);
 
             var result = new QueryResult<ProgramInfoDto>
             {
                 Items = returnArray,
-                TotalRecordCount = returnArray.Length
+                TotalRecordCount = programList.Count
             };
 
             return result;
@@ -729,7 +740,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 programs = programs.Where(i => i.HasAired == val);
             }
 
-            var serviceName = ActiveService.Name;
+            if (query.IsMovie.HasValue)
+            {
+                programs = programs.Where(p => p.IsMovie == query.IsMovie.Value);
+            }
 
             var programList = programs.ToList();
 
@@ -739,7 +753,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
 
             programs = programList.OrderBy(i => i.HasImage(ImageType.Primary) ? 0 : 1)
-                .ThenByDescending(i => GetRecommendationScore(i, user.Id, serviceName, genres))
+                .ThenByDescending(i => GetRecommendationScore(i, user.Id, genres))
                 .ThenBy(i => i.StartDate);
 
             if (query.Limit.HasValue)
@@ -750,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             programList = programs.ToList();
 
-            await RefreshIfNeeded(programList, cancellationToken).ConfigureAwait(false);
+            RefreshIfNeeded(programList);
 
             var returnArray = programList.ToArray();
 
@@ -789,7 +803,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             return result;
         }
 
-        private int GetRecommendationScore(LiveTvProgram program, Guid userId, string serviceName, Dictionary<string, Genre> genres)
+        private int GetRecommendationScore(LiveTvProgram program, Guid userId, Dictionary<string, Genre> genres)
         {
             var score = 0;
 
@@ -803,7 +817,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 score++;
             }
 
-            var internalChannelId = _tvDtoService.GetInternalChannelId(serviceName, program.ExternalChannelId);
+            var internalChannelId = _tvDtoService.GetInternalChannelId(program.ServiceName, program.ExternalChannelId);
             var channel = GetInternalChannel(internalChannelId);
 
             var channelUserdata = _userDataManager.GetUserData(userId, channel.GetUserDataKey());
@@ -861,11 +875,17 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private async Task AddRecordingInfo(IEnumerable<ProgramInfoDto> programs, CancellationToken cancellationToken)
         {
-            var timers = await ActiveService.GetTimersAsync(cancellationToken).ConfigureAwait(false);
-            var timerList = timers.ToList();
+            var timers = new Dictionary<string, List<TimerInfo>>();
 
             foreach (var program in programs)
             {
+                List<TimerInfo> timerList;
+                if (!timers.TryGetValue(program.ServiceName, out timerList))
+                {
+                    var tempTimers = await GetService(program.ServiceName).GetTimersAsync(cancellationToken).ConfigureAwait(false);
+                    timers[program.ServiceName] = timerList = tempTimers.ToList();
+                }
+
                 var timer = timerList.FirstOrDefault(i => string.Equals(i.ProgramId, program.ExternalId, StringComparison.OrdinalIgnoreCase));
 
                 if (timer != null)
@@ -904,15 +924,43 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            // Avoid implicitly captured closure
-            var service = ActiveService;
+            var numComplete = 0;
+            double progressPerService = _services.Count == 0
+                ? 0
+                : 1 / _services.Count;
 
-            if (service == null)
+            foreach (var service in _services)
             {
-                progress.Report(100);
-                return;
+                cancellationToken.ThrowIfCancellationRequested();
+
+                try
+                {
+                    var innerProgress = new ActionableProgress<double>();
+                    innerProgress.RegisterAction(p => progress.Report(p * progressPerService));
+
+                    await RefreshChannelsInternal(service, innerProgress, cancellationToken).ConfigureAwait(false);
+                }
+                catch (OperationCanceledException)
+                {
+                    throw;
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error refreshing channels for service", ex);
+                }
+
+                numComplete++;
+                double percent = numComplete;
+                percent /= _services.Count;
+
+                progress.Report(100 * percent);
             }
 
+            progress.Report(100);
+        }
+
+        private async Task RefreshChannelsInternal(ILiveTvService service, IProgress<double> progress, CancellationToken cancellationToken)
+        {
             progress.Report(10);
 
             var allChannels = await GetChannels(service, cancellationToken).ConfigureAwait(false);
@@ -974,9 +1022,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
                     var channelPrograms = await service.GetProgramsAsync(currentChannel.ExternalId, start, end, cancellationToken).ConfigureAwait(false);
 
-                    var programEntities = channelPrograms.Select(program => GetProgram(program, currentChannel.ChannelType, service.Name, cancellationToken));
-
-                    programs.AddRange(programEntities);
+                    foreach (var program in channelPrograms)
+                    {
+                        programs.Add(await GetProgram(program, currentChannel.ChannelType, service.Name, cancellationToken).ConfigureAwait(false));
+                    }
                 }
                 catch (OperationCanceledException)
                 {
@@ -1024,14 +1073,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private async Task DeleteOldPrograms(List<Guid> currentIdList, IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var service = ActiveService;
-
-            if (service == null)
-            {
-                progress.Report(100);
-                return;
-            }
-
             var list = _itemRepo.GetItemsOfType(typeof(LiveTvProgram)).ToList();
 
             var numComplete = 0;
@@ -1081,77 +1122,75 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task<QueryResult<BaseItem>> GetInternalRecordings(RecordingQuery query, CancellationToken cancellationToken)
         {
-            var service = ActiveService;
-
-            if (service == null)
+            var tasks = _services.Select(async i =>
             {
-                return new QueryResult<BaseItem>
+                try
                 {
-                    Items = new BaseItem[] { }
-                };
-            }
+                    var recs = await i.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
+                    return recs.Select(r => new Tuple<RecordingInfo, ILiveTvService>(r, i));
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error getting recordings", ex);
+                    return new List<Tuple<RecordingInfo, ILiveTvService>>();
+                }
+            });
+            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
+            var recordings = results.SelectMany(i => i.ToList());
 
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
 
-            var recordings = await service.GetRecordingsAsync(cancellationToken).ConfigureAwait(false);
-
             if (user != null && !IsLiveTvEnabled(user))
             {
-                recordings = new List<RecordingInfo>();
+                recordings = new List<Tuple<RecordingInfo, ILiveTvService>>();
             }
 
             if (!string.IsNullOrEmpty(query.ChannelId))
             {
                 var guid = new Guid(query.ChannelId);
 
-                var currentServiceName = service.Name;
-
                 recordings = recordings
-                    .Where(i => _tvDtoService.GetInternalChannelId(currentServiceName, i.ChannelId) == guid);
+                    .Where(i => _tvDtoService.GetInternalChannelId(i.Item2.Name, i.Item1.ChannelId) == guid);
             }
 
             if (!string.IsNullOrEmpty(query.Id))
             {
                 var guid = new Guid(query.Id);
 
-                var currentServiceName = service.Name;
-
                 recordings = recordings
-                    .Where(i => _tvDtoService.GetInternalRecordingId(currentServiceName, i.Id) == guid);
+                    .Where(i => _tvDtoService.GetInternalRecordingId(i.Item2.Name, i.Item1.Id) == guid);
             }
 
             if (!string.IsNullOrEmpty(query.GroupId))
             {
                 var guid = new Guid(query.GroupId);
 
-                recordings = recordings.Where(i => GetRecordingGroupIds(i).Contains(guid));
+                recordings = recordings.Where(i => GetRecordingGroupIds(i.Item1).Contains(guid));
             }
 
             if (query.IsInProgress.HasValue)
             {
                 var val = query.IsInProgress.Value;
-                recordings = recordings.Where(i => (i.Status == RecordingStatus.InProgress) == val);
+                recordings = recordings.Where(i => (i.Item1.Status == RecordingStatus.InProgress) == val);
             }
 
             if (query.Status.HasValue)
             {
                 var val = query.Status.Value;
-                recordings = recordings.Where(i => (i.Status == val));
+                recordings = recordings.Where(i => (i.Item1.Status == val));
             }
 
             if (!string.IsNullOrEmpty(query.SeriesTimerId))
             {
                 var guid = new Guid(query.SeriesTimerId);
 
-                var currentServiceName = service.Name;
-
                 recordings = recordings
-                    .Where(i => _tvDtoService.GetInternalSeriesTimerId(currentServiceName, i.SeriesTimerId) == guid);
+                    .Where(i => _tvDtoService.GetInternalSeriesTimerId(i.Item2.Name, i.Item1.SeriesTimerId) == guid);
             }
 
-            recordings = recordings.OrderByDescending(i => i.StartDate);
+            recordings = recordings.OrderByDescending(i => i.Item1.StartDate);
 
-            IEnumerable<ILiveTvRecording> entities = await GetEntities(recordings, service.Name, cancellationToken).ConfigureAwait(false);
+            IEnumerable<ILiveTvRecording> entities = await GetEntities(recordings, cancellationToken).ConfigureAwait(false);
 
             if (user != null)
             {
@@ -1181,16 +1220,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task<QueryResult<RecordingInfoDto>> GetRecordings(RecordingQuery query, CancellationToken cancellationToken)
         {
-            var service = ActiveService;
-
-            if (service == null)
-            {
-                return new QueryResult<RecordingInfoDto>
-                {
-                    Items = new RecordingInfoDto[] { }
-                };
-            }
-
             var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId);
 
             var internalResult = await GetInternalRecordings(query, cancellationToken).ConfigureAwait(false);
@@ -1198,6 +1227,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             var returnArray = internalResult.Items.Cast<ILiveTvRecording>()
                 .Select(i =>
                 {
+                    var service = GetService(i);
+
                     var channel = string.IsNullOrEmpty(i.RecordingInfo.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, i.RecordingInfo.ChannelId));
                     return _tvDtoService.GetRecordingInfoDto(i, channel, service, user);
                 })
@@ -1210,35 +1241,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             };
         }
 
-        private Task<ILiveTvRecording[]> GetEntities(IEnumerable<RecordingInfo> recordings, string serviceName, CancellationToken cancellationToken)
+        private Task<ILiveTvRecording[]> GetEntities(IEnumerable<Tuple<RecordingInfo, ILiveTvService>> recordings, CancellationToken cancellationToken)
         {
-            var tasks = recordings.Select(i => GetRecording(i, serviceName, cancellationToken));
+            var tasks = recordings.Select(i => GetRecording(i.Item1, i.Item2.Name, cancellationToken));
 
             return Task.WhenAll(tasks);
         }
 
-        private IEnumerable<ILiveTvService> GetServices(string serviceName, string channelId)
-        {
-            IEnumerable<ILiveTvService> services = _services;
-
-            if (string.IsNullOrEmpty(serviceName) && !string.IsNullOrEmpty(channelId))
-            {
-                var channel = GetInternalChannel(channelId);
-
-                if (channel != null)
-                {
-                    serviceName = channel.ServiceName;
-                }
-            }
-
-            if (!string.IsNullOrEmpty(serviceName))
-            {
-                services = services.Where(i => string.Equals(i.Name, serviceName, StringComparison.OrdinalIgnoreCase));
-            }
-
-            return services;
-        }
-
         public async Task<QueryResult<TimerInfoDto>> GetTimers(TimerQuery query, CancellationToken cancellationToken)
         {
             var service = ActiveService;
@@ -1266,7 +1275,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             {
                 var program = string.IsNullOrEmpty(i.ProgramId) ?
                     null :
-                    await GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"), cancellationToken).ConfigureAwait(false);
+                    GetInternalProgram(_tvDtoService.GetInternalProgramId(service.Name, i.ProgramId).ToString("N"));
 
                 var channel = string.IsNullOrEmpty(i.ChannelId) ? null : GetInternalChannel(_tvDtoService.GetInternalChannelId(service.Name, i.ChannelId));
 
@@ -1293,8 +1302,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 throw new ResourceNotFoundException(string.Format("Recording with Id {0} not found", recordingId));
             }
 
-            var service = GetServices(recording.ServiceName, null)
-                .First();
+            var service = GetService(recording.ServiceName);
 
             await service.DeleteRecordingAsync(recording.ExternalId, CancellationToken.None).ConfigureAwait(false);
         }
@@ -1308,8 +1316,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 throw new ResourceNotFoundException(string.Format("Timer with Id {0} not found", id));
             }
 
-            var service = GetServices(timer.ServiceName, null)
-                .First();
+            var service = GetService(timer.ServiceName);
 
             await service.CancelTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
         }
@@ -1323,8 +1330,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 throw new ResourceNotFoundException(string.Format("Timer with Id {0} not found", id));
             }
 
-            var service = GetServices(timer.ServiceName, null)
-                .First();
+            var service = GetService(timer.ServiceName);
 
             await service.CancelSeriesTimerAsync(timer.ExternalId, CancellationToken.None).ConfigureAwait(false);
         }
@@ -1402,14 +1408,14 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             var channel = GetInternalChannel(id);
 
-            var currentProgram = await GetCurrentProgram(channel.ExternalId, cancellationToken).ConfigureAwait(false);
+            var currentProgram = GetCurrentProgram(channel.ExternalId);
 
             var dto = _tvDtoService.GetChannelInfoDto(channel, currentProgram, user);
 
             return dto;
         }
 
-        private async Task<LiveTvProgram> GetCurrentProgram(string externalChannelId, CancellationToken cancellationToken)
+        private LiveTvProgram GetCurrentProgram(string externalChannelId)
         {
             var now = DateTime.UtcNow;
 
@@ -1421,14 +1427,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
             if (program != null)
             {
-                await RefreshIfNeeded(program, cancellationToken).ConfigureAwait(false);
+                RefreshIfNeeded(program);
             }
 
             return program;
         }
 
-        private async Task<SeriesTimerInfo> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
+        private async Task<Tuple<SeriesTimerInfo,ILiveTvService>> GetNewTimerDefaultsInternal(CancellationToken cancellationToken, LiveTvProgram program = null)
         {
+            var service = program != null && !string.IsNullOrWhiteSpace(program.ServiceName) ?
+                GetService(program) :
+                _services.FirstOrDefault();
+
             ProgramInfo programInfo = null;
 
             if (program != null)
@@ -1462,29 +1472,29 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 };
             }
 
-            var info = await ActiveService.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
+            var info = await service.GetNewTimerDefaultsAsync(cancellationToken, programInfo).ConfigureAwait(false);
 
             info.Id = null;
 
-            return info;
+            return new Tuple<SeriesTimerInfo, ILiveTvService>(info, service);
         }
 
         public async Task<SeriesTimerInfoDto> GetNewTimerDefaults(CancellationToken cancellationToken)
         {
             var info = await GetNewTimerDefaultsInternal(cancellationToken).ConfigureAwait(false);
 
-            var obj = _tvDtoService.GetSeriesTimerInfoDto(info, ActiveService, null);
+            var obj = _tvDtoService.GetSeriesTimerInfoDto(info.Item1, info.Item2, null);
 
             return obj;
         }
 
         public async Task<SeriesTimerInfoDto> GetNewTimerDefaults(string programId, CancellationToken cancellationToken)
         {
-            var program = await GetInternalProgram(programId, cancellationToken).ConfigureAwait(false);
+            var program = GetInternalProgram(programId);
             var programDto = await GetProgram(programId, cancellationToken).ConfigureAwait(false);
 
             var defaults = await GetNewTimerDefaultsInternal(cancellationToken, program).ConfigureAwait(false);
-            var info = _tvDtoService.GetSeriesTimerInfoDto(defaults, ActiveService, null);
+            var info = _tvDtoService.GetSeriesTimerInfoDto(defaults.Item1, defaults.Item2, null);
 
             info.Days = new List<DayOfWeek>
             {
@@ -1512,7 +1522,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task CreateTimer(TimerInfoDto timer, CancellationToken cancellationToken)
         {
-            var service = string.IsNullOrEmpty(timer.ServiceName) ? ActiveService : GetServices(timer.ServiceName, null).First();
+            var service = GetService(timer.ServiceName);
 
             var info = await _tvDtoService.GetTimerInfo(timer, true, this, cancellationToken).ConfigureAwait(false);
 
@@ -1525,7 +1535,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public async Task CreateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
         {
-            var service = string.IsNullOrEmpty(timer.ServiceName) ? ActiveService : GetServices(timer.ServiceName, null).First();
+            var service = GetService(timer.ServiceName);
 
             var info = await _tvDtoService.GetSeriesTimerInfo(timer, true, this, cancellationToken).ConfigureAwait(false);
 
@@ -1540,7 +1550,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             var info = await _tvDtoService.GetTimerInfo(timer, false, this, cancellationToken).ConfigureAwait(false);
 
-            var service = string.IsNullOrEmpty(timer.ServiceName) ? ActiveService : GetServices(timer.ServiceName, null).First();
+            var service = GetService(timer.ServiceName);
 
             await service.UpdateTimerAsync(info, cancellationToken).ConfigureAwait(false);
         }
@@ -1549,7 +1559,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             var info = await _tvDtoService.GetSeriesTimerInfo(timer, false, this, cancellationToken).ConfigureAwait(false);
 
-            var service = string.IsNullOrEmpty(timer.ServiceName) ? ActiveService : GetServices(timer.ServiceName, null).First();
+            var service = GetService(timer.ServiceName);
 
             await service.UpdateSeriesTimerAsync(info, cancellationToken).ConfigureAwait(false);
         }
@@ -1815,16 +1825,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             var services = await GetServiceInfos(CancellationToken.None).ConfigureAwait(false);
             var servicesList = services.ToList();
 
-            var activeServiceInfo = ActiveService == null ? null :
-                servicesList.FirstOrDefault(i => string.Equals(i.Name, ActiveService.Name, StringComparison.OrdinalIgnoreCase));
-
             var info = new LiveTvInfo
             {
                 Services = servicesList.ToList(),
-                ActiveServiceName = activeServiceInfo == null ? null : activeServiceInfo.Name,
-                IsEnabled = ActiveService != null,
-                Status = activeServiceInfo == null ? LiveTvServiceStatus.Unavailable : activeServiceInfo.Status,
-                StatusMessage = activeServiceInfo == null ? null : activeServiceInfo.StatusMessage
+                IsEnabled = servicesList.Count > 0
             };
 
             info.EnabledUsers = _userManager.Users
@@ -1837,15 +1841,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         private bool IsLiveTvEnabled(User user)
         {
-            return user.Policy.EnableLiveTvAccess && ActiveService != null;
+            return user.Policy.EnableLiveTvAccess && Services.Count > 0;
         }
 
         public IEnumerable<User> GetEnabledUsers()
         {
-            var service = ActiveService;
-
             return _userManager.Users
-                .Where(i => i.Policy.EnableLiveTvAccess && service != null);
+                .Where(IsLiveTvEnabled);
         }
 
         /// <summary>
@@ -1871,7 +1873,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         public async Task<Folder> GetInternalLiveTvFolder(string userId, CancellationToken cancellationToken)
         {
             var name = _localization.GetLocalizedString("ViewTypeLiveTV");
-            return await _libraryManager.GetNamedView(name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false);
+            var user = _userManager.GetUserById(userId);
+            return await _libraryManager.GetNamedView(user, name, "livetv", "zz_" + name, cancellationToken).ConfigureAwait(false);
         }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
index 05cbfede0c..de2351434f 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
@@ -52,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         public bool IsHidden
         {
-            get { return _liveTvManager.ActiveService == null; }
+            get { return _liveTvManager.Services.Count == 0; }
         }
 
         public bool IsEnabled
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
index bd31baef92..a14c8b6ea6 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json
index 832668c82c..41f12525d1 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/bg_BG.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "\u041f\u0440\u0438\u0432\u044a\u0440\u0436\u0435\u043d\u0441\u043a\u043e\u0442\u043e \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u043e\u0441\u0438\u0433\u0443\u0440\u044f\u0432\u0430 \u0434\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0438 \u043e\u0431\u043b\u0430\u0433\u0438, \u043a\u0430\u0442\u043e \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u043f\u044a\u0440\u0432\u043e\u043a\u043b\u0430\u0441\u043d\u0438 \u043f\u043b\u044a\u0433\u0438\u043d\u0438, \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0438\u0442\u0435, \u0438 \u0434\u0440\u0443\u0433\u0438. {0} \u041d\u0430\u0443\u0447\u0435\u0442\u0435 \u043f\u043e\u0432\u0435\u0447\u0435 {1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "\u0414\u043e\u0431\u0440\u0435 \u0434\u043e\u0448\u043b\u0438 \u0432 \u0433\u043b\u0430\u0432\u043d\u0438\u044f \u043f\u0430\u043d\u0435\u043b \u043d\u0430 Media Browser",
     "HeaderWelcomeToMediaBrowserWebClient": "\u0414\u043e\u0431\u0440\u0435 \u0434\u043e\u0448\u043b\u0438 \u0432 \u0443\u0435\u0431 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043d\u0430 Media Browser",
     "ButtonTakeTheTour": "\u0420\u0430\u0437\u0433\u043b\u0435\u0434\u0430\u0439 \u043d\u0430\u043e\u043a\u043e\u043b\u043e",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
index 7dbc537653..7db7c4de82 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
index 3f287eedc5..70f0526cff 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "U\u017eivatel\u00e9",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Vyhled\u00e1v\u00e1n\u00ed",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Um\u011blec",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
index 62a59144f5..cb14eb9817 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Brugere",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
index 5fe350b0d8..45caf19735 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Danke. Dein Unterst\u00fctzerschl\u00fcssel wurde aktualisiert.",
     "MessageKeyRemoved": "Danke. Ihr Unterst\u00fctzerschl\u00fcssel wurde entfernt.",
     "ErrorLaunchingChromecast": "W\u00e4hrend des startens von Chromecast ist ein Fehler aufgetreten. Bitte stelle sicher, dass dein Ger\u00e4te mit dem WLAN verbunden ist.",
+    "MessageErrorLoadingSupporterInfo": "Es trat ein Fehler beim laden der Unterst\u00fctzer-Informationen auf. Bitte versuchen Sie es sp\u00e4ter erneut.",
+    "MessageLinkYourSupporterKey": "Verkn\u00fcpfen Sie Ihren Unterst\u00fctzer-Schl\u00fcssel mit bis zu {0} Media Browser Connect Anwendern um Zugriff auf folgende Apps zu erhalten:",
+    "HeaderConfirmRemoveUser": "Entferne Benutzer",
+    "MessageSwipeDownOnRemoteControl": "Willkommen zur Fernsteuerung. Streichen Sie irgendwo auf dem Bildschirm nach unten um dorthin zur\u00fcck zu gehen, von wo aus Sie kamen.",
+    "MessageConfirmRemoveConnectSupporter": "M\u00f6chten Sie wirklich zus\u00e4tzliche Unterst\u00fctzer-Features von diesem Anwender entfernen?",
+    "ValueTimeLimitSingleHour": "Zeitlimit: 1 Stunde",
+    "ValueTimeLimitMultiHour": "Zeitlimit: {0} Stunden",
+    "HeaderUsers": "Benutzer",
+    "PluginCategoryGeneral": "Allgemein",
+    "PluginCategoryContentProvider": "Inhaltsanbieter",
+    "PluginCategoryScreenSaver": "Bildschirmschoner",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Synchronisation",
+    "PluginCategorySocialIntegration": "Soziale Netzwerke",
+    "PluginCategoryNotifications": "Benachrichtigungen",
+    "PluginCategoryMetadata": "Metadaten",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Kan\u00e4le",
     "HeaderSearch": "Suche",
     "ValueDateCreated": "Erstellungsdatum: {0}",
     "LabelArtist": "Interpret",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Zu Sammlung hinzuf\u00fcgen",
     "HeaderSelectCertificatePath": "W\u00e4hlen Sie einen Zertifikat Ordner",
     "ConfirmMessageScheduledTaskButton": "Diese Aufgabe l\u00e4uft normalerweise automatisch als geplante Aufgabe. Sie kann jedoch auch manuell von hier gestartet werden. F\u00fcr Einstellungen der geplanten Aufgaben schauen Sie hier:",
-    "HeaderSupporterBenefit": "Eine Unterst\u00fctzer-Mitgliedschaft bietet weitere Vorteile, wie z.B. den Zugriff auf premium Plugins, weitere Internet-Channels und mehr. {0}Erfahren Sie mehr{1}.",
+    "HeaderSupporterBenefit": "Eine Unterst\u00fctzer-Mitgliedschaft bietet weitere Funktionen wie z.B. Zugriff auf die Synchronisation, Premium-Plugins, Internet Kan\u00e4le und mehr. {0}Erfahren Sie mehr{1}.",
     "LabelSyncNoTargetsHelp": "Es sieht so aus als w\u00fcrden Sie aktuell keine Apps verwenden, die Synchronisation unterst\u00fctzen.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Willkommen zur Media Browser \u00dcbersicht",
     "HeaderWelcomeToMediaBrowserWebClient": "Willkommen zum Media Browser Web Client",
     "ButtonTakeTheTour": "Mache die Tour",
     "HeaderWelcomeBack": "Willkommen zur\u00fcck!",
+    "TitleSync": "Synchronisation",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Gehen Sie auf Erkundung und erfahren Sie was neu ist",
     "MessageNoSyncJobsFound": "Keine Synchronisierungs-Aufgaben gefunden. Um Synchronisierungs-Aufgaben zu erstellen verwenden Sie die dazugeh\u00f6rige Funktion im Web-Interface.",
     "HeaderLibraryAccess": "Bibliothekszugriff",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installiert",
     "LabelNumberReviews": "{0} Bewertungen",
     "LabelFree": "Frei",
+    "HeaderPlaybackError": "Wiedergabefehler",
+    "MessagePlaybackErrorNotAllowed": "Sie sind nicht befugt diese Inhalte wiederzugeben. Bitte kontaktieren Sie Ihren Systemadministrator f\u00fcr weitere Details.",
+    "MessagePlaybackErrorNoCompatibleStream": "Es sind aktuell keine kompatiblen Streams verf\u00fcgbar. Bitte versuchen Sie es sp\u00e4ter erneut.",
+    "MessagePlaybackErrorRateLimitExceeded": "Ihr Wiedergabelimit wurde \u00fcberschritten. Bitte kontaktieren Sie Ihren Systemadministrator f\u00fcr weitere Details.",
     "HeaderSelectAudio": "W\u00e4hle Audio",
     "HeaderSelectSubtitles": "W\u00f6hle Untertitel",
     "ButtonMarkForRemoval": "Entferne von Ger\u00e4t",
     "ButtonUnmarkForRemoval": "Abbrechen von Entfernen von Ger\u00e4t",
-    "LabelSyncQualityHelp": "Verwenden Sie \"hohe Qualit\u00e4t\" um die maximale vom Ger\u00e4t unterst\u00fctze Qualit\u00e4t zu verwenden. Mittlere und niedrige Qualit\u00e4t wird die erlaubte Datenrate reduzieren. Original wird die original Datei synchronisieren, egal ob diese vom Ger\u00e4t abgespielt werden kann oder nicht.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Erzwungen)",
     "LabelDefaultForcedStream": "(Standard\/Erzwungen)",
@@ -254,7 +277,7 @@
     "ButtonOpenInNewTab": "\u00d6ffne in neuem Tab",
     "ButtonShuffle": "Zufallswiedergabe",
     "ButtonInstantMix": "Schnellmix",
-    "ButtonResume": "Wiederholen",
+    "ButtonResume": "Fortsetzen",
     "HeaderScenes": "Szenen",
     "HeaderAudioTracks": "Audiospuren",
     "HeaderLibraries": "Bibliotheken",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieren {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Synchronisieren",
     "SyncMedia": "Synchronisiere Medien",
     "HeaderCancelSyncJob": "Synchronisierung abbrechen",
-    "CancelSyncJobConfirmation": "M\u00f6chten Sie die Synchronisations-Aufgabe wirklich abbrechen?",
+    "CancelSyncJobConfirmation": "Der Abbruch der Synchronisation wird bereits synchronisierte Medien bei der n\u00e4chsten Synchronisation vom Ger\u00e4t l\u00f6schen. M\u00f6chten Sie wirklich fortfahren?",
     "TabSync": "Synchronisieren",
     "MessagePleaseSelectDeviceToSyncTo": "Bitte w\u00e4hlen Sie ein zu synchronisierendes Ger\u00e4t.",
     "MessageSyncJobCreated": "Synchronisations-Aufgabe erstellt.",
     "LabelSyncTo": "Synchronisiere mit:",
     "LabelSyncJobName": "Synchronisations-Aufgabe:",
     "LabelQuality": "Qualit\u00e4t:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "Hoch",
-    "OptionMedium": "Mittel",
-    "OptionLow": "Niedrig",
     "HeaderSettings": "Einstellungen",
     "OptionAutomaticallySyncNewContent": "Synchronisiere neue Inhalte automatisch",
     "OptionAutomaticallySyncNewContentHelp": "Neue Inhalte dieser Kategorie werden automatisch mit dem Ger\u00e4t synchronisiert.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synchronisiert",
     "SyncJobItemStatusFailed": "Fehlgeschlagen.",
     "SyncJobItemStatusRemovedFromDevice": "Entfernt von Ger\u00e4t",
-    "SyncJobItemStatusCancelled": "Abgebrochen"
+    "SyncJobItemStatusCancelled": "Abgebrochen",
+    "LabelProfile": "Profil:",
+    "LabelBitrateMbps": "Datenrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
index 8703cb0c97..25065a2457 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b5\u03c2 ",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
index 1401bd38c0..a4793dc387 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
index 7511535ffe..b09d9c1487 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
index 5dd40d0b93..3a80d21d96 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Gracias. Su clave de seguidor ha sido actualizada.",
     "MessageKeyRemoved": "Gracias. Su clave de seguidor ha sido eliminada.",
     "ErrorLaunchingChromecast": "Ha habido un error al lanzar chromecast. Asegurese que su dispositivo est\u00e1 conectado a su red inal\u00e1mbrica.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Usuarios",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Buscar",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artista",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Vienvenido al Cliente Web de Media Browser",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} instalado",
     "LabelNumberReviews": "{0} Revisiones",
     "LabelFree": "Libre",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Seleccionar Audio",
     "HeaderSelectSubtitles": "Seleccionar Subt\u00edtulos",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Por defecto)",
     "LabelForcedStream": "(Forzado)",
     "LabelDefaultForcedStream": "(Por defecto\/Forzado)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
index 2f607cc4e8..20a4117d74 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Gracias. Su clave de aficionado ha sido actualizada.",
     "MessageKeyRemoved": "Gracias. Su clave de aficionado ha sido eliminada.",
     "ErrorLaunchingChromecast": "Hubo un error iniciando chromecast. Por favor aseg\u00farate de que tu dispositivo este conectado a tu red inalambrica",
+    "MessageErrorLoadingSupporterInfo": "Se present\u00f3 un error al cargar la informaci\u00f3n del aficionado. Por favor int\u00e9ntelo m\u00e1s tarde.",
+    "MessageLinkYourSupporterKey": "Ligue su clave de aficionado con hasta {0} miembros de Media Browser Connect para disfrutar de acceso gratuito a las siguientes apps:",
+    "HeaderConfirmRemoveUser": "Eliminar Usuario",
+    "MessageSwipeDownOnRemoteControl": "Bienvenido a control remoto. Deslice hacia abajo en cualquier parte de esta pantalla para regresar al sitio anterior.",
+    "MessageConfirmRemoveConnectSupporter": "\u00bfEst\u00e1 seguro de querer eliminar los beneficios adicionales de aficionado de este usuario?",
+    "ValueTimeLimitSingleHour": "L\u00edmite de tiempo: 1 hora",
+    "ValueTimeLimitMultiHour": "L\u00edmite de tiempo: {0} horas",
+    "HeaderUsers": "Usuarios",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Proveedores de Contenido",
+    "PluginCategoryScreenSaver": "Protectores de Pantalla",
+    "PluginCategoryTheme": "Temas",
+    "PluginCategorySync": "Sinc",
+    "PluginCategorySocialIntegration": "Redes Sociales",
+    "PluginCategoryNotifications": "Notificaciones",
+    "PluginCategoryMetadata": "Metadatos",
+    "PluginCategoryLiveTV": "TV en Vivo",
+    "PluginCategoryChannel": "Canales",
     "HeaderSearch": "Buscar",
     "ValueDateCreated": "Fecha de creaci\u00f3n: {0}",
     "LabelArtist": "Artista",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Agregar a colecci\u00f3n",
     "HeaderSelectCertificatePath": "Seleccione Trayectoria del Certificado",
     "ConfirmMessageScheduledTaskButton": "Esta operaci\u00f3n normalmente es ejecutada autom\u00e1ticamente como una tarea programada. Tambi\u00e9n puede ser ejecutada manualmente desde aqu\u00ed. Para configurar la tarea programada, vea:",
-    "HeaderSupporterBenefit": "La membres\u00eda de aficionado proporciona beneficios adicionales tales como acceso a complementos premium, contenido de canales de Internet y m\u00e1s. {0}Conocer m\u00e1s{1}.",
+    "HeaderSupporterBenefit": "La membres\u00eda de aficionado proporciona beneficios adicionales tales como acceso a sincronizaci\u00f3n, complementos premium, contenido de canales de Internet y m\u00e1s. {0}Conocer m\u00e1s{1}.",
     "LabelSyncNoTargetsHelp": "Parece que actualmente no cuentas con ninguna app que soporte sinc.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Bienvenido al Panel de Control de Media Browser",
     "HeaderWelcomeToMediaBrowserWebClient": "Bienvenido al Cliente Web de Media Browser",
     "ButtonTakeTheTour": "Haga el recorrido",
     "HeaderWelcomeBack": "\u00a1Bienvenido nuevamente!",
+    "TitleSync": "Sinc",
+    "TitlePlugins": "Complementos",
     "ButtonTakeTheTourToSeeWhatsNew": "Inice el tour para ver que hay de nuevo",
     "MessageNoSyncJobsFound": "No se han encontrado trabajos de sincronizaci\u00f3n. Cree trabajos de sincronizaci\u00f3n empleando los botones de Sinc que se encuentran en la intergface web.",
     "HeaderLibraryAccess": "Acceso a la Biblioteca",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} instalado",
     "LabelNumberReviews": "{0} Rese\u00f1as",
     "LabelFree": "Gratis",
+    "HeaderPlaybackError": "Error de Reproducci\u00f3n",
+    "MessagePlaybackErrorNotAllowed": "Actualmente no esta autorizado para reproducir este contenido. Por favor contacte a su administrador de sistema para mas informaci\u00f3n.",
+    "MessagePlaybackErrorNoCompatibleStream": "No hay streams compatibles en este en este momento. Por favor intente de nuevo mas tarde.",
+    "MessagePlaybackErrorRateLimitExceeded": "Su limite de transferencia ha sido excedido. Por favor contacte a su administrador de sistema para mas informaci\u00f3n.",
     "HeaderSelectAudio": "Seleccionar Audio",
     "HeaderSelectSubtitles": "Seleccionar Subtitulos",
     "ButtonMarkForRemoval": "Remover de dispositivo",
     "ButtonUnmarkForRemoval": "Cancelar remover de dispositivo",
-    "LabelSyncQualityHelp": "Utilice alta calidad para la calidad m\u00e1xima soportada por el dispositivo. La calidad media y baja reducir\u00e1n la tasa de bits permitida. Original har\u00e1 sinc del archivo original, sin importar si el dispositivo es capaz de reproducirlo o no.",
     "LabelDefaultStream": "(Por defecto)",
     "LabelForcedStream": "(Forzado)",
     "LabelDefaultForcedStream": "(Por Defecto\/Forzado)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Estrenos: {0}",
     "ValueStudio": "Estudio: {0}",
     "ValueStudios": "Estudios: {0}",
+    "ValueStatus": "Estado: {0}",
     "ValueSpecialEpisodeName": "Especial: {0}",
     "LabelLimit": "L\u00edmite:",
     "ValueLinks": "Enlaces: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "SInc",
     "SyncMedia": "Sincronizar Medios",
     "HeaderCancelSyncJob": "Cancelar Sinc.",
-    "CancelSyncJobConfirmation": "\u00bfEsta seguro de querer cancelar este trabajo de sincronizaci\u00f3n?",
+    "CancelSyncJobConfirmation": "Cancelando el trabajo de sincronizaci\u00f3n eliminara los medios sincronizados del dispositivo durante el pr\u00f3ximo proceso de sincronizaci\u00f3n. \u00bfEsta seguro de que desea continuar?",
     "TabSync": "Sinc",
     "MessagePleaseSelectDeviceToSyncTo": "Por favor seleccione un dispositivo con el que desea sincronizar.",
     "MessageSyncJobCreated": "Trabajo de sinc. creado.",
     "LabelSyncTo": "Sincronizar con:",
     "LabelSyncJobName": "Nombre del trabajo de sinc:",
     "LabelQuality": "Calidad:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "Alta",
-    "OptionMedium": "Media",
-    "OptionLow": "Baja",
     "HeaderSettings": "Configuraci\u00f3n",
     "OptionAutomaticallySyncNewContent": "Sincronizar autom\u00e1ticamente nuevos contenidos",
     "OptionAutomaticallySyncNewContentHelp": "Los contenidos nuevos agregados a esta categor\u00eda ser\u00e1n sincronizados autom\u00e1ticamente con el dispositivo.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Sincronizado",
     "SyncJobItemStatusFailed": "Fall\u00f3",
     "SyncJobItemStatusRemovedFromDevice": "Eliminado del dispositivo",
-    "SyncJobItemStatusCancelled": "Cancelado"
+    "SyncJobItemStatusCancelled": "Cancelado",
+    "LabelProfile": "Perf\u00edl:",
+    "LabelBitrateMbps": "Tasa de bits (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
index 48bdfb16c5..49541164d4 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
index 75a0432f57..765f517994 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Merci. Votre cl\u00e9 de supporteur a \u00e9t\u00e9 mise \u00e0 jour.",
     "MessageKeyRemoved": "Merci. Votre cl\u00e9 de supporteur a \u00e9t\u00e9 supprim\u00e9e.",
     "ErrorLaunchingChromecast": "Une erreur a \u00e9t\u00e9 rencontr\u00e9e lors du lancement de Chromecast. Veuillez vous assurer que votre appareil est bien connect\u00e9 \u00e0 votre r\u00e9seau sans-fil.",
+    "MessageErrorLoadingSupporterInfo": "Il y a eu une erreur lors du chargement des informations de supporter. Veuillez r\u00e9essayer plus tard.",
+    "MessageLinkYourSupporterKey": "Liez votre cl\u00e9 de supporteur avec {0} utilisateurs de Media Browser Connect au maximum et profitez d'un acc\u00e8s gratuit aux applications suivantes :",
+    "HeaderConfirmRemoveUser": "Supprimer l'utilisateur",
+    "MessageSwipeDownOnRemoteControl": "Bienvenue dans le contr\u00f4le \u00e0 distance. Glissez vers le base n'importe o\u00f9 sur cet \u00e9cran pour revenir l\u00e0 d'o\u00f9 vous venez",
+    "MessageConfirmRemoveConnectSupporter": "Etes-vous s\u00fbr de vouloir supprimer les avantages additionnels de supporteur pour cet utilisateur ?",
+    "ValueTimeLimitSingleHour": "Limite de temps : 1 heure",
+    "ValueTimeLimitMultiHour": "Limite de temps : {0} heures",
+    "HeaderUsers": "Utilisateurs",
+    "PluginCategoryGeneral": "G\u00e9n\u00e9ral",
+    "PluginCategoryContentProvider": "Fournisseurs de contenus",
+    "PluginCategoryScreenSaver": "Ecrans de veille",
+    "PluginCategoryTheme": "Th\u00e8mes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "R\u00e9seaux sociaux",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "M\u00e9tadonn\u00e9es",
+    "PluginCategoryLiveTV": "TV en Direct",
+    "PluginCategoryChannel": "Cha\u00eenes",
     "HeaderSearch": "Recherche",
     "ValueDateCreated": "Date de cr\u00e9ation : {0}",
     "LabelArtist": "Artiste",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Ajouter \u00e0 une collection",
     "HeaderSelectCertificatePath": "S\u00e9lectionnez le chemin du certificat",
     "ConfirmMessageScheduledTaskButton": "Cette op\u00e9ration s'ex\u00e9cute normalement automatiquement en tant que t\u00e2che planifi\u00e9e. Elle peut aussi \u00eatre ex\u00e9cut\u00e9e manuellement ici. Pour configurer la t\u00e2che planifi\u00e9e, voir:",
-    "HeaderSupporterBenefit": "Un partenariat de membre supporteur apporte des avantages suppl\u00e9mentaires, comme l'acc\u00e8s aux plugins premiums, aux contenus des cha\u00eenes Internet, et plus encore. {0}En savoir plus{1}.",
+    "HeaderSupporterBenefit": "Un partenariat de membre supporteur apporte des avantages suppl\u00e9mentaires, comme l'acc\u00e8s \u00e0 la synchronisation, aux plugins premiums, aux contenus des cha\u00eenes Internet, et plus encore. {0}En savoir plus{1}.",
     "LabelSyncNoTargetsHelp": "Il semble que vous n'ayez actuellement aucune application qui supporte la synchronisation.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Bienvenue dans le centre de contr\u00f4le de Media browser",
     "HeaderWelcomeToMediaBrowserWebClient": "Bienvenue sur le client web de Media Browser",
     "ButtonTakeTheTour": "Visite guid\u00e9e",
     "HeaderWelcomeBack": "Bienvenue !",
+    "TitleSync": "Sync.",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Suivez le guide pour d\u00e9couvrir les nouveaut\u00e9s",
     "MessageNoSyncJobsFound": "Aucune t\u00e2che de synchronisation trouv\u00e9e. Vous pouvez cr\u00e9er des t\u00e2ches de synchronisation gr\u00e2ce aux boutons 'Synchroniser' partout dans l'interface web.",
     "HeaderLibraryAccess": "Acc\u00e8s \u00e0 la librairie",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} install\u00e9(s)",
     "LabelNumberReviews": "{0} Critique(s)",
     "LabelFree": "Gratuit",
+    "HeaderPlaybackError": "Erreur de lecture",
+    "MessagePlaybackErrorNotAllowed": "Vous n'\u00eates pas autoris\u00e9 \u00e0 lire ce contenu. Veuillez contacter votre administrateur syst\u00e8me pour plus de d\u00e9tails.",
+    "MessagePlaybackErrorNoCompatibleStream": "Aucun flux compatible n'est actuellement disponible. Veuillez r\u00e9essayer plus tard.",
+    "MessagePlaybackErrorRateLimitExceeded": "Vous avez d\u00e9pass\u00e9 votre limite de lecture. Veuillez contacter votre administrateur syst\u00e8me pour plus de d\u00e9tails.",
     "HeaderSelectAudio": "S\u00e9lectionner audio",
     "HeaderSelectSubtitles": "S\u00e9lectionner sous-titres",
     "ButtonMarkForRemoval": "Supprimer de l'appareil",
     "ButtonUnmarkForRemoval": "Annuler la suppression de l'appareil",
-    "LabelSyncQualityHelp": "Utilisez haute qualit\u00e9 pour obtenir la qualit\u00e9 maximale support\u00e9e par l'appareil. Moyenne et basse qualit\u00e9 r\u00e9duiront le d\u00e9bit autoris\u00e9. Original synchronisera le fichier d'origine, ind\u00e9pendamment de la capacit\u00e9 de l'appareil \u00e0 le lire.",
     "LabelDefaultStream": "(Par d\u00e9faut)",
     "LabelForcedStream": "(Forc\u00e9)",
     "LabelDefaultForcedStream": "(Par d\u00e9faut\/Forc\u00e9)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Acteurs principaux {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Etat: {0}",
     "ValueSpecialEpisodeName": "Sp\u00e9cial - {0}",
     "LabelLimit": "Limite :",
     "ValueLinks": "Liens : {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync. les m\u00e9dias",
     "HeaderCancelSyncJob": "Annuler la sync.",
-    "CancelSyncJobConfirmation": "\u00cates vous sure de vouloir annuler cette synchronisation?",
+    "CancelSyncJobConfirmation": "L'annulation d'une t\u00e2che de synchronisation provoquera la suppression des m\u00e9dias synchronis\u00e9s lors la prochaine ex\u00e9cution de la synchronisation. Etes-vous s\u00fbr de vouloir continuer ?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Veuillez s\u00e9lectionner un p\u00e9riph\u00e9rique avec lequel se synchroniser.",
     "MessageSyncJobCreated": "Job de synchronisation cr\u00e9\u00e9.",
     "LabelSyncTo": "Synchronis\u00e9 avec:",
     "LabelSyncJobName": "Nom du job de synchronisation:",
     "LabelQuality": "Qualit\u00e9:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "Haute",
-    "OptionMedium": "Moyenne",
-    "OptionLow": "Basse",
     "HeaderSettings": "Param\u00e8tres",
     "OptionAutomaticallySyncNewContent": "Synchroniser automatiquement le nouveau contenu",
     "OptionAutomaticallySyncNewContentHelp": "Les nouveaux contenus ajout\u00e9s \u00e0 cette cat\u00e9gorie seront automatiquement synchronis\u00e9s avec le p\u00e9riph\u00e9rique.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synchronis\u00e9",
     "SyncJobItemStatusFailed": "Echou\u00e9",
     "SyncJobItemStatusRemovedFromDevice": "Supprim\u00e9 de l'appareil",
-    "SyncJobItemStatusCancelled": "Annul\u00e9"
+    "SyncJobItemStatusCancelled": "Annul\u00e9",
+    "LabelProfile": "Profil :",
+    "LabelBitrateMbps": "D\u00e9bit (Mbps) :"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
index ebe3166c3b..22b96c5948 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u05de\u05e9\u05ea\u05de\u05e9\u05d9\u05dd",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
index 39d34a76e7..e6095bb532 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Korisnici",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json
new file mode 100644
index 0000000000..da7219d2b6
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/hu.json
@@ -0,0 +1,748 @@
+{
+    "SettingsSaved": "Settings saved.",
+    "AddUser": "Add User",
+    "Users": "Users",
+    "Delete": "Delete",
+    "Administrator": "Administrator",
+    "Password": "Password",
+    "DeleteImage": "Delete Image",
+    "MessageThankYouForSupporting": "Thank you for supporting Media Browser.",
+    "MessagePleaseSupportMediaBrowser": "Please support Media Browser.",
+    "DeleteImageConfirmation": "Are you sure you wish to delete this image?",
+    "FileReadCancelled": "The file read has been canceled.",
+    "FileNotFound": "File not found.",
+    "FileReadError": "An error occurred while reading the file.",
+    "DeleteUser": "Delete User",
+    "DeleteUserConfirmation": "Are you sure you wish to delete this user?",
+    "PasswordResetHeader": "Reset Password",
+    "PasswordResetComplete": "The password has been reset.",
+    "PinCodeResetComplete": "The pin code has been reset.",
+    "PasswordResetConfirmation": "Are you sure you wish to reset the password?",
+    "PinCodeResetConfirmation": "Are you sure you wish to reset the pin code?",
+    "HeaderPinCodeReset": "Reset Pin Code",
+    "PasswordSaved": "Password saved.",
+    "PasswordMatchError": "Password and password confirmation must match.",
+    "OptionRelease": "Official Release",
+    "OptionBeta": "Beta",
+    "OptionDev": "Dev (Unstable)",
+    "UninstallPluginHeader": "Uninstall Plugin",
+    "UninstallPluginConfirmation": "Are you sure you wish to uninstall {0}?",
+    "NoPluginConfigurationMessage": "This plugin has nothing to configure.",
+    "NoPluginsInstalledMessage": "You have no plugins installed.",
+    "BrowsePluginCatalogMessage": "Browse our plugin catalog to view available plugins.",
+    "MessageKeyEmailedTo": "Key emailed to {0}.",
+    "MessageKeysLinked": "Keys linked.",
+    "HeaderConfirmation": "Confirmation",
+    "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
+    "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
+    "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
+    "HeaderSearch": "Search",
+    "ValueDateCreated": "Date created: {0}",
+    "LabelArtist": "Artist",
+    "LabelMovie": "Movie",
+    "LabelMusicVideo": "Music Video",
+    "LabelEpisode": "Episode",
+    "LabelSeries": "Sorozatok",
+    "LabelStopping": "Stopping",
+    "LabelCancelled": "(cancelled)",
+    "LabelFailed": "(failed)",
+    "ButtonHelp": "Help",
+    "ButtonSave": "Save",
+    "ButtonDownload": "Download",
+    "SyncJobStatusQueued": "Queued",
+    "SyncJobStatusConverting": "Converting",
+    "SyncJobStatusFailed": "Failed",
+    "SyncJobStatusCancelled": "Cancelled",
+    "SyncJobStatusCompleted": "Synced",
+    "SyncJobStatusReadyToTransfer": "Ready to Transfer",
+    "SyncJobStatusTransferring": "Transferring",
+    "SyncJobStatusCompletedWithError": "Synced with errors",
+    "SyncJobItemStatusReadyToTransfer": "Ready to Transfer",
+    "LabelCollection": "Collection",
+    "HeaderAddToCollection": "Add to Collection",
+    "NewCollectionNameExample": "Example: Star Wars Collection",
+    "OptionSearchForInternetMetadata": "Search the internet for artwork and metadata",
+    "LabelSelectCollection": "Select collection:",
+    "HeaderDevices": "Devices",
+    "ButtonScheduledTasks": "Scheduled tasks",
+    "MessageItemsAdded": "Items added",
+    "ButtonAddToCollection": "Add to collection",
+    "HeaderSelectCertificatePath": "Select Certificate Path",
+    "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
+    "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
+    "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
+    "ButtonTakeTheTour": "Take the tour",
+    "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
+    "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
+    "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
+    "HeaderLibraryAccess": "Library Access",
+    "HeaderChannelAccess": "Channel Access",
+    "HeaderDeviceAccess": "Device Access",
+    "HeaderSelectDevices": "Select Devices",
+    "ButtonCancelItem": "Cancel item",
+    "ButtonQueueForRetry": "Queue for retry",
+    "ButtonReenable": "Re-enable",
+    "ButtonLearnMore": "Learn more",
+    "SyncJobItemStatusSyncedMarkForRemoval": "Marked for removal",
+    "LabelAbortedByServerShutdown": "(Aborted by server shutdown)",
+    "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
+    "HeaderDeleteTaskTrigger": "Delete Task Trigger",
+    "HeaderTaskTriggers": "Task Triggers",
+    "MessageDeleteTaskTrigger": "Are you sure you wish to delete this task trigger?",
+    "MessageNoPluginsInstalled": "You have no plugins installed.",
+    "LabelVersionInstalled": "{0} installed",
+    "LabelNumberReviews": "{0} Reviews",
+    "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
+    "HeaderSelectAudio": "Select Audio",
+    "HeaderSelectSubtitles": "Select Subtitles",
+    "ButtonMarkForRemoval": "Remove from device",
+    "ButtonUnmarkForRemoval": "Cancel removal from device",
+    "LabelDefaultStream": "(Default)",
+    "LabelForcedStream": "(Forced)",
+    "LabelDefaultForcedStream": "(Default\/Forced)",
+    "LabelUnknownLanguage": "Unknown language",
+    "MessageConfirmSyncJobItemCancellation": "Are you sure you wish to cancel this item?",
+    "ButtonMute": "Mute",
+    "ButtonUnmute": "Unmute",
+    "ButtonStop": "Stop",
+    "ButtonNextTrack": "Next Track",
+    "ButtonPause": "Pause",
+    "ButtonPlay": "Play",
+    "ButtonEdit": "Edit",
+    "ButtonQueue": "Queue",
+    "ButtonPlayTrailer": "Play trailer",
+    "ButtonPlaylist": "Playlist",
+    "ButtonPreviousTrack": "Previous Track",
+    "LabelEnabled": "Enabled",
+    "LabelDisabled": "Disabled",
+    "ButtonMoreInformation": "More Information",
+    "LabelNoUnreadNotifications": "No unread notifications.",
+    "ButtonViewNotifications": "View notifications",
+    "ButtonMarkTheseRead": "Mark these read",
+    "ButtonClose": "Close",
+    "LabelAllPlaysSentToPlayer": "All plays will be sent to the selected player.",
+    "MessageInvalidUser": "Invalid username or password. Please try again.",
+    "HeaderLoginFailure": "Login Failure",
+    "HeaderAllRecordings": "All Recordings",
+    "RecommendationBecauseYouLike": "Because you like {0}",
+    "RecommendationBecauseYouWatched": "Because you watched {0}",
+    "RecommendationDirectedBy": "Directed by {0}",
+    "RecommendationStarring": "Starring {0}",
+    "HeaderConfirmRecordingCancellation": "Confirm Recording Cancellation",
+    "MessageConfirmRecordingCancellation": "Are you sure you wish to cancel this recording?",
+    "MessageRecordingCancelled": "Recording cancelled.",
+    "HeaderConfirmSeriesCancellation": "Confirm Series Cancellation",
+    "MessageConfirmSeriesCancellation": "Are you sure you wish to cancel this series?",
+    "MessageSeriesCancelled": "Series cancelled.",
+    "HeaderConfirmRecordingDeletion": "Confirm Recording Deletion",
+    "MessageConfirmRecordingDeletion": "Are you sure you wish to delete this recording?",
+    "MessageRecordingDeleted": "Recording deleted.",
+    "ButonCancelRecording": "Cancel Recording",
+    "MessageRecordingSaved": "Recording saved.",
+    "OptionSunday": "Sunday",
+    "OptionMonday": "Monday",
+    "OptionTuesday": "Tuesday",
+    "OptionWednesday": "Wednesday",
+    "OptionThursday": "Thursday",
+    "OptionFriday": "Friday",
+    "OptionSaturday": "Saturday",
+    "HeaderConfirmDeletion": "Confirm Deletion",
+    "MessageConfirmPathSubstitutionDeletion": "Are you sure you wish to delete this path substitution?",
+    "LiveTvUpdateAvailable": "(Update available)",
+    "LabelVersionUpToDate": "Up to date!",
+    "ButtonResetTuner": "Reset tuner",
+    "HeaderResetTuner": "Reset Tuner",
+    "MessageConfirmResetTuner": "Are you sure you wish to reset this tuner? Any active players or recordings will be abruptly stopped.",
+    "ButtonCancelSeries": "Cancel Series",
+    "HeaderSeriesRecordings": "Series Recordings",
+    "LabelAnytime": "Any time",
+    "StatusRecording": "Recording",
+    "StatusWatching": "Watching",
+    "StatusRecordingProgram": "Recording {0}",
+    "StatusWatchingProgram": "Watching {0}",
+    "HeaderSplitMedia": "Split Media Apart",
+    "MessageConfirmSplitMedia": "Are you sure you wish to split the media sources into separate items?",
+    "HeaderError": "Error",
+    "MessagePleaseSelectOneItem": "Please select at least one item.",
+    "MessagePleaseSelectTwoItems": "Please select at least two items.",
+    "MessageTheFollowingItemsWillBeGrouped": "The following titles will be grouped into one item:",
+    "MessageConfirmItemGrouping": "Media Browser clients will automatically choose the optimal version to play based on device and network performance. Are you sure you wish to continue?",
+    "HeaderResume": "Resume",
+    "HeaderMyViews": "My Views",
+    "HeaderLibraryFolders": "Media Folders",
+    "HeaderLatestMedia": "Latest Media",
+    "ButtonMoreItems": "More...",
+    "ButtonMore": "More",
+    "HeaderFavoriteMovies": "Favorite Movies",
+    "HeaderFavoriteShows": "Favorite Shows",
+    "HeaderFavoriteEpisodes": "Favorite Episodes",
+    "HeaderFavoriteGames": "Favorite Games",
+    "HeaderRatingsDownloads": "Rating \/ Downloads",
+    "HeaderConfirmProfileDeletion": "Confirm Profile Deletion",
+    "MessageConfirmProfileDeletion": "Are you sure you wish to delete this profile?",
+    "HeaderSelectServerCachePath": "Select Server Cache Path",
+    "HeaderSelectTranscodingPath": "Select Transcoding Temporary Path",
+    "HeaderSelectImagesByNamePath": "Select Images By Name Path",
+    "HeaderSelectMetadataPath": "Select Metadata Path",
+    "HeaderSelectServerCachePathHelp": "Browse or enter the path to use for server cache files. The folder must be writeable.",
+    "HeaderSelectTranscodingPathHelp": "Browse or enter the path to use for transcoding temporary files. The folder must be writeable.",
+    "HeaderSelectImagesByNamePathHelp": "Browse or enter the path to your items by name folder. The folder must be writeable.",
+    "HeaderSelectMetadataPathHelp": "Browse or enter the path you'd like to store metadata within. The folder must be writeable.",
+    "HeaderSelectChannelDownloadPath": "Select Channel Download Path",
+    "HeaderSelectChannelDownloadPathHelp": "Browse or enter the path to use for storing channel cache files. The folder must be writeable.",
+    "OptionNewCollection": "New...",
+    "ButtonAdd": "Add",
+    "ButtonRemove": "Remove",
+    "LabelChapterDownloaders": "Chapter downloaders:",
+    "LabelChapterDownloadersHelp": "Enable and rank your preferred chapter downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
+    "HeaderFavoriteAlbums": "Favorite Albums",
+    "HeaderLatestChannelMedia": "Latest Channel Items",
+    "ButtonOrganizeFile": "Organize File",
+    "ButtonDeleteFile": "Delete File",
+    "HeaderOrganizeFile": "Organize File",
+    "HeaderDeleteFile": "Delete File",
+    "StatusSkipped": "Skipped",
+    "StatusFailed": "Failed",
+    "StatusSuccess": "Success",
+    "MessageFileWillBeDeleted": "The following file will be deleted:",
+    "MessageSureYouWishToProceed": "Are you sure you wish to proceed?",
+    "MessageDuplicatesWillBeDeleted": "In addition the following dupliates will be deleted:",
+    "MessageFollowingFileWillBeMovedFrom": "The following file will be moved from:",
+    "MessageDestinationTo": "to:",
+    "HeaderSelectWatchFolder": "Select Watch Folder",
+    "HeaderSelectWatchFolderHelp": "Browse or enter the path to your watch folder. The folder must be writeable.",
+    "OrganizePatternResult": "Result: {0}",
+    "HeaderRestart": "Restart",
+    "HeaderShutdown": "Shutdown",
+    "MessageConfirmRestart": "Are you sure you wish to restart Media Browser Server?",
+    "MessageConfirmShutdown": "Are you sure you wish to shutdown Media Browser Server?",
+    "ButtonUpdateNow": "Update Now",
+    "ValueItemCount": "{0} item",
+    "ValueItemCountPlural": "{0} items",
+    "NewVersionOfSomethingAvailable": "A new version of {0} is available!",
+    "VersionXIsAvailableForDownload": "Version {0} is now available for download.",
+    "LabelVersionNumber": "Version {0}",
+    "LabelPlayMethodTranscoding": "Transcoding",
+    "LabelPlayMethodDirectStream": "Direct Streaming",
+    "LabelPlayMethodDirectPlay": "Direct Playing",
+    "LabelAudioCodec": "Audio: {0}",
+    "LabelVideoCodec": "Video: {0}",
+    "LabelLocalAccessUrl": "Local access: {0}",
+    "LabelRemoteAccessUrl": "Remote access: {0}",
+    "LabelRunningOnPort": "Running on http port {0}.",
+    "LabelRunningOnPorts": "Running on http port {0}, and https port {1}.",
+    "HeaderLatestFromChannel": "Latest from {0}",
+    "LabelUnknownLanaguage": "Unknown language",
+    "HeaderCurrentSubtitles": "Current Subtitles",
+    "MessageDownloadQueued": "The download has been queued.",
+    "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?",
+    "ButtonRemoteControl": "Remote Control",
+    "HeaderLatestTvRecordings": "Latest Recordings",
+    "ButtonOk": "Ok",
+    "ButtonCancel": "Cancel",
+    "ButtonRefresh": "Refresh",
+    "LabelCurrentPath": "Current path:",
+    "HeaderSelectMediaPath": "Select Media Path",
+    "HeaderSelectPath": "Select Path",
+    "ButtonNetwork": "Network",
+    "MessageDirectoryPickerInstruction": "Network paths can be entered manually in the event the Network button fails to locate your devices. For example, {0} or {1}.",
+    "HeaderMenu": "Menu",
+    "ButtonOpen": "Open",
+    "ButtonOpenInNewTab": "Open in new tab",
+    "ButtonShuffle": "Shuffle",
+    "ButtonInstantMix": "Instant mix",
+    "ButtonResume": "Resume",
+    "HeaderScenes": "Scenes",
+    "HeaderAudioTracks": "Audio Tracks",
+    "HeaderLibraries": "Libraries",
+    "HeaderSubtitles": "Subtitles",
+    "HeaderVideoQuality": "Video Quality",
+    "MessageErrorPlayingVideo": "There was an error playing the video.",
+    "MessageEnsureOpenTuner": "Please ensure there is an open tuner availalble.",
+    "ButtonHome": "Home",
+    "ButtonDashboard": "Dashboard",
+    "ButtonReports": "Reports",
+    "ButtonMetadataManager": "Metadata Manager",
+    "HeaderTime": "Time",
+    "HeaderName": "Name",
+    "HeaderAlbum": "Album",
+    "HeaderAlbumArtist": "Album Artist",
+    "HeaderArtist": "Artist",
+    "LabelAddedOnDate": "Added {0}",
+    "ButtonStart": "Start",
+    "HeaderChannels": "Channels",
+    "HeaderMediaFolders": "Media Folders",
+    "HeaderBlockItemsWithNoRating": "Block content with no rating information:",
+    "OptionBlockOthers": "Others",
+    "OptionBlockTvShows": "TV Shows",
+    "OptionBlockTrailers": "Trailers",
+    "OptionBlockMusic": "Music",
+    "OptionBlockMovies": "Movies",
+    "OptionBlockBooks": "Books",
+    "OptionBlockGames": "Games",
+    "OptionBlockLiveTvPrograms": "Live TV Programs",
+    "OptionBlockLiveTvChannels": "Live TV Channels",
+    "OptionBlockChannelContent": "Internet Channel Content",
+    "ButtonRevoke": "Revoke",
+    "MessageConfirmRevokeApiKey": "Are you sure you wish to revoke this api key? The application's connection to Media Browser will be abruptly terminated.",
+    "HeaderConfirmRevokeApiKey": "Revoke Api Key",
+    "ValueContainer": "Container: {0}",
+    "ValueAudioCodec": "Audio Codec: {0}",
+    "ValueVideoCodec": "Video Codec: {0}",
+    "ValueCodec": "Codec: {0}",
+    "ValueConditions": "Conditions: {0}",
+    "LabelAll": "All",
+    "HeaderDeleteImage": "Delete Image",
+    "MessageFileNotFound": "File not found.",
+    "MessageFileReadError": "An error occurred reading this file.",
+    "ButtonNextPage": "Next Page",
+    "ButtonPreviousPage": "Previous Page",
+    "ButtonMoveLeft": "Move left",
+    "ButtonMoveRight": "Move right",
+    "ButtonBrowseOnlineImages": "Browse online images",
+    "HeaderDeleteItem": "Delete Item",
+    "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
+    "MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
+    "MessageValueNotCorrect": "The value entered is not correct. Please try again.",
+    "MessageItemSaved": "Item saved.",
+    "MessagePleaseAcceptTermsOfServiceBeforeContinuing": "Please accept the terms of service before continuing.",
+    "OptionEnded": "Ended",
+    "OptionContinuing": "Continuing",
+    "OptionOff": "Off",
+    "OptionOn": "On",
+    "ButtonSettings": "Settings",
+    "ButtonUninstall": "Uninstall",
+    "HeaderFields": "Fields",
+    "HeaderFieldsHelp": "Slide a field to 'off' to lock it and prevent it's data from being changed.",
+    "HeaderLiveTV": "Live TV",
+    "MissingLocalTrailer": "Missing local trailer.",
+    "MissingPrimaryImage": "Missing primary image.",
+    "MissingBackdropImage": "Missing backdrop image.",
+    "MissingLogoImage": "Missing logo image.",
+    "MissingEpisode": "Missing episode.",
+    "OptionScreenshots": "Screenshots",
+    "OptionBackdrops": "Backdrops",
+    "OptionImages": "Images",
+    "OptionKeywords": "Keywords",
+    "OptionTags": "Tags",
+    "OptionStudios": "Studios",
+    "OptionName": "Name",
+    "OptionOverview": "Overview",
+    "OptionGenres": "Genres",
+    "OptionParentalRating": "Parental Rating",
+    "OptionPeople": "People",
+    "OptionRuntime": "Runtime",
+    "OptionProductionLocations": "Production Locations",
+    "OptionBirthLocation": "Birth Location",
+    "LabelAllChannels": "All channels",
+    "LabelLiveProgram": "LIVE",
+    "LabelNewProgram": "NEW",
+    "LabelPremiereProgram": "PREMIERE",
+    "LabelHDProgram": "HD",
+    "HeaderChangeFolderType": "Change Content Type",
+    "HeaderChangeFolderTypeHelp": "To change the type, please remove and rebuild the folder with the new type.",
+    "HeaderAlert": "Alert",
+    "MessagePleaseRestart": "Please restart to finish updating.",
+    "ButtonRestart": "Restart",
+    "MessagePleaseRefreshPage": "Please refresh this page to receive new updates from the server.",
+    "ButtonHide": "Hide",
+    "MessageSettingsSaved": "Settings saved.",
+    "ButtonSignOut": "Sign Out",
+    "ButtonMyProfile": "My Profile",
+    "ButtonMyPreferences": "My Preferences",
+    "MessageBrowserDoesNotSupportWebSockets": "This browser does not support web sockets. For a better experience, try a newer browser such as Chrome, Firefox, IE10+, Safari (iOS) or Opera.",
+    "LabelInstallingPackage": "Installing {0}",
+    "LabelPackageInstallCompleted": "{0} installation completed.",
+    "LabelPackageInstallFailed": "{0} installation failed.",
+    "LabelPackageInstallCancelled": "{0} installation cancelled.",
+    "TabServer": "Server",
+    "TabUsers": "Users",
+    "TabLibrary": "Library",
+    "TabMetadata": "Metadata",
+    "TabDLNA": "DLNA",
+    "TabLiveTV": "Live TV",
+    "TabAutoOrganize": "Auto-Organize",
+    "TabPlugins": "Plugins",
+    "TabAdvanced": "Advanced",
+    "TabHelp": "Help",
+    "TabScheduledTasks": "Scheduled Tasks",
+    "ButtonFullscreen": "Teljes k\u00e9perny\u0151",
+    "ButtonAudioTracks": "Audio Tracks",
+    "ButtonSubtitles": "Subtitles",
+    "ButtonScenes": "Scenes",
+    "ButtonQuality": "Quality",
+    "HeaderNotifications": "Notifications",
+    "HeaderSelectPlayer": "Select Player:",
+    "ButtonSelect": "Select",
+    "ButtonNew": "New",
+    "MessageInternetExplorerWebm": "For best results with Internet Explorer please install the WebM playback plugin.",
+    "HeaderVideoError": "Video Error",
+    "ButtonAddToPlaylist": "Add to playlist",
+    "HeaderAddToPlaylist": "Add to Playlist",
+    "LabelName": "Name:",
+    "ButtonSubmit": "Submit",
+    "LabelSelectPlaylist": "Playlist:",
+    "OptionNewPlaylist": "New playlist...",
+    "MessageAddedToPlaylistSuccess": "Ok",
+    "ButtonView": "View",
+    "ButtonViewSeriesRecording": "View series recording",
+    "ValueOriginalAirDate": "Original air date: {0}",
+    "ButtonRemoveFromPlaylist": "Remove from playlist",
+    "HeaderSpecials": "Specials",
+    "HeaderTrailers": "Trailers",
+    "HeaderAudio": "Audio",
+    "HeaderResolution": "Resolution",
+    "HeaderVideo": "Video",
+    "HeaderRuntime": "Runtime",
+    "HeaderCommunityRating": "Community rating",
+    "HeaderParentalRating": "Parental rating",
+    "HeaderReleaseDate": "Release date",
+    "HeaderDateAdded": "Date added",
+    "HeaderSeries": "Series",
+    "HeaderSeason": "Season",
+    "HeaderSeasonNumber": "Season number",
+    "HeaderNetwork": "Network",
+    "HeaderYear": "Year",
+    "HeaderGameSystem": "Game system",
+    "HeaderPlayers": "Players",
+    "HeaderEmbeddedImage": "Embedded image",
+    "HeaderTrack": "Track",
+    "HeaderDisc": "Disc",
+    "OptionMovies": "Movies",
+    "OptionCollections": "Collections",
+    "OptionSeries": "Series",
+    "OptionSeasons": "Seasons",
+    "OptionEpisodes": "Episodes",
+    "OptionGames": "Games",
+    "OptionGameSystems": "Game systems",
+    "OptionMusicArtists": "Music artists",
+    "OptionMusicAlbums": "Music albums",
+    "OptionMusicVideos": "Music videos",
+    "OptionSongs": "Songs",
+    "OptionHomeVideos": "Home videos",
+    "OptionBooks": "Books",
+    "OptionAdultVideos": "Adult videos",
+    "ButtonUp": "Up",
+    "ButtonDown": "Down",
+    "LabelMetadataReaders": "Metadata readers:",
+    "LabelMetadataReadersHelp": "Rank your preferred local metadata sources in order of priority. The first file found will be read.",
+    "LabelMetadataDownloaders": "Metadata downloaders:",
+    "LabelMetadataDownloadersHelp": "Enable and rank your preferred metadata downloaders in order of priority. Lower priority downloaders will only be used to fill in missing information.",
+    "LabelMetadataSavers": "Metadata savers:",
+    "LabelMetadataSaversHelp": "Choose the file formats to save your metadata to.",
+    "LabelImageFetchers": "Image fetchers:",
+    "LabelImageFetchersHelp": "Enable and rank your preferred image fetchers in order of priority.",
+    "ButtonQueueAllFromHere": "Queue all from here",
+    "ButtonPlayAllFromHere": "Play all from here",
+    "LabelDynamicExternalId": "{0} Id:",
+    "HeaderIdentify": "Identify Item",
+    "PersonTypePerson": "Person",
+    "LabelTitleDisplayOrder": "Title display order:",
+    "OptionSortName": "Sort name",
+    "OptionReleaseDate": "Release date",
+    "LabelSeasonNumber": "Season number:",
+    "LabelDiscNumber": "Disc number",
+    "LabelParentNumber": "Parent number",
+    "LabelEpisodeNumber": "Episode number:",
+    "LabelTrackNumber": "Track number:",
+    "LabelNumber": "Number:",
+    "LabelReleaseDate": "Release date:",
+    "LabelEndDate": "End date:",
+    "LabelYear": "Year:",
+    "LabelDateOfBirth": "Date of birth:",
+    "LabelBirthYear": "Birth year:",
+    "LabelBirthDate": "Birth date:",
+    "LabelDeathDate": "Death date:",
+    "HeaderRemoveMediaLocation": "Remove Media Location",
+    "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?",
+    "HeaderRenameMediaFolder": "Rename Media Folder",
+    "LabelNewName": "New name:",
+    "HeaderAddMediaFolder": "Add Media Folder",
+    "HeaderAddMediaFolderHelp": "Name (Movies, Music, TV, etc):",
+    "HeaderRemoveMediaFolder": "Remove Media Folder",
+    "MessageTheFollowingLocationWillBeRemovedFromLibrary": "The following media locations will be removed from your library:",
+    "MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?",
+    "ButtonRename": "Rename",
+    "ButtonChangeType": "Change type",
+    "HeaderMediaLocations": "Media Locations",
+    "LabelContentTypeValue": "Content type: {0}",
+    "LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
+    "FolderTypeUnset": "Unset (mixed content)",
+    "FolderTypeMovies": "Movies",
+    "FolderTypeMusic": "Music",
+    "FolderTypeAdultVideos": "Adult videos",
+    "FolderTypePhotos": "Photos",
+    "FolderTypeMusicVideos": "Music videos",
+    "FolderTypeHomeVideos": "Home videos",
+    "FolderTypeGames": "Games",
+    "FolderTypeBooks": "Books",
+    "FolderTypeTvShows": "TV",
+    "TabMovies": "Movies",
+    "TabSeries": "Series",
+    "TabEpisodes": "Episodes",
+    "TabTrailers": "Trailers",
+    "TabGames": "Games",
+    "TabAlbums": "Albums",
+    "TabSongs": "Songs",
+    "TabMusicVideos": "Music Videos",
+    "BirthPlaceValue": "Birth place: {0}",
+    "DeathDateValue": "Died: {0}",
+    "BirthDateValue": "Born: {0}",
+    "HeaderLatestReviews": "Latest Reviews",
+    "HeaderPluginInstallation": "Plugin Installation",
+    "MessageAlreadyInstalled": "This version is already installed.",
+    "ValueReviewCount": "{0} Reviews",
+    "MessageYouHaveVersionInstalled": "You currently have version {0} installed.",
+    "MessageTrialExpired": "The trial period for this feature has expired",
+    "MessageTrialWillExpireIn": "The trial period for this feature will expire in {0} day(s)",
+    "MessageInstallPluginFromApp": "This plugin must be installed from with in the app you intend to use it in.",
+    "ValuePriceUSD": "Price: {0} (USD)",
+    "MessageFeatureIncludedWithSupporter": "You are registered for this feature, and will be able to continue using it with an active supporter membership.",
+    "MessageChangeRecurringPlanConfirm": "After completing this transaction you will need to cancel your previous recurring donation from within your PayPal account. Thank you for supporting Media Browser.",
+    "MessageSupporterMembershipExpiredOn": "Your supporter membership expired on {0}.",
+    "MessageYouHaveALifetimeMembership": "You have a lifetime supporter membership. You can provide additional donations on a one-time or recurring basis using the options below. Thank you for supporting Media Browser.",
+    "MessageYouHaveAnActiveRecurringMembership": "You have an active {0} membership. You can upgrade your plan using the options below.",
+    "ButtonDelete": "Delete",
+    "HeaderMediaBrowserAccountAdded": "Media Browser Account Added",
+    "MessageMediaBrowserAccountAdded": "The Media Browser account has been added to this user.",
+    "MessagePendingMediaBrowserAccountAdded": "The Media Browser account has been added to this user. An email will be sent to the owner of the account. The invitation will need to be confirmed by clicking a link within the email.",
+    "HeaderMediaBrowserAccountRemoved": "Media Browser Account Removed",
+    "MessageMediaBrowserAccontRemoved": "The Media Browser account has been removed from this user.",
+    "TooltipLinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderUnrated": "Unrated",
+    "ValueDiscNumber": "Disc {0}",
+    "HeaderUnknownDate": "Unknown Date",
+    "HeaderUnknownYear": "Unknown Year",
+    "ValueMinutes": "{0} min",
+    "ButtonPlayExternalPlayer": "Play with external player",
+    "HeaderSelectExternalPlayer": "Select External Player",
+    "HeaderExternalPlayerPlayback": "External Player Playback",
+    "ButtonImDone": "I'm Done",
+    "OptionWatched": "Watched",
+    "OptionUnwatched": "Unwatched",
+    "ExternalPlayerPlaystateOptionsHelp": "Specify how you would like to resume playing this video next time.",
+    "LabelMarkAs": "Mark as:",
+    "OptionInProgress": "In-Progress",
+    "LabelResumePoint": "Resume point:",
+    "ValueOneMovie": "1 movie",
+    "ValueMovieCount": "{0} movies",
+    "ValueOneTrailer": "1 trailer",
+    "ValueTrailerCount": "{0} trailers",
+    "ValueOneSeries": "1 series",
+    "ValueSeriesCount": "{0} series",
+    "ValueOneEpisode": "1 episode",
+    "ValueEpisodeCount": "{0} episodes",
+    "ValueOneGame": "1 game",
+    "ValueGameCount": "{0} games",
+    "ValueOneAlbum": "1 album",
+    "ValueAlbumCount": "{0} albums",
+    "ValueOneSong": "1 song",
+    "ValueSongCount": "{0} songs",
+    "ValueOneMusicVideo": "1 music video",
+    "ValueMusicVideoCount": "{0} music videos",
+    "HeaderOffline": "Offline",
+    "HeaderUnaired": "Unaired",
+    "HeaderMissing": "Missing",
+    "ButtonWebsite": "Website",
+    "TooltipFavorite": "Favorite",
+    "TooltipLike": "Like",
+    "TooltipDislike": "Dislike",
+    "TooltipPlayed": "Played",
+    "ValueSeriesYearToPresent": "{0}-Present",
+    "ValueAwards": "Awards: {0}",
+    "ValueBudget": "Budget: {0}",
+    "ValueRevenue": "Revenue: {0}",
+    "ValuePremiered": "Premiered {0}",
+    "ValuePremieres": "Premieres {0}",
+    "ValueStudio": "Studio: {0}",
+    "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
+    "ValueSpecialEpisodeName": "Special - {0}",
+    "LabelLimit": "Limit:",
+    "ValueLinks": "Links: {0}",
+    "HeaderPeople": "People",
+    "HeaderCastAndCrew": "Cast & Crew",
+    "ValueArtist": "Artist: {0}",
+    "ValueArtists": "Artists: {0}",
+    "HeaderTags": "Tags",
+    "MediaInfoCameraMake": "Camera make",
+    "MediaInfoCameraModel": "Camera model",
+    "MediaInfoAltitude": "Altitude",
+    "MediaInfoAperture": "Aperture",
+    "MediaInfoExposureTime": "Exposure time",
+    "MediaInfoFocalLength": "Focal length",
+    "MediaInfoOrientation": "Orientation",
+    "MediaInfoIsoSpeedRating": "Iso speed rating",
+    "MediaInfoLatitude": "Latitude",
+    "MediaInfoLongitude": "Longitude",
+    "MediaInfoShutterSpeed": "Shutter speed",
+    "MediaInfoSoftware": "Software",
+    "HeaderIfYouLikeCheckTheseOut": "If you like {0}, check these out...",
+    "HeaderPlotKeywords": "Plot Keywords",
+    "HeaderMovies": "Movies",
+    "HeaderAlbums": "Albums",
+    "HeaderGames": "Games",
+    "HeaderBooks": "Books",
+    "HeaderEpisodes": "Episodes",
+    "HeaderSeasons": "Seasons",
+    "HeaderTracks": "Tracks",
+    "HeaderItems": "Items",
+    "HeaderOtherItems": "Other Items",
+    "ButtonFullReview": "Full review",
+    "ValueAsRole": "as {0}",
+    "ValueGuestStar": "Guest star",
+    "MediaInfoSize": "Size",
+    "MediaInfoPath": "Path",
+    "MediaInfoFormat": "Format",
+    "MediaInfoContainer": "Container",
+    "MediaInfoDefault": "Default",
+    "MediaInfoForced": "Forced",
+    "MediaInfoExternal": "External",
+    "MediaInfoTimestamp": "Timestamp",
+    "MediaInfoPixelFormat": "Pixel format",
+    "MediaInfoBitDepth": "Bit depth",
+    "MediaInfoSampleRate": "Sample rate",
+    "MediaInfoBitrate": "Bitrate",
+    "MediaInfoChannels": "Channels",
+    "MediaInfoLayout": "Layout",
+    "MediaInfoLanguage": "Language",
+    "MediaInfoCodec": "Codec",
+    "MediaInfoProfile": "Profile",
+    "MediaInfoLevel": "Level",
+    "MediaInfoAspectRatio": "Aspect ratio",
+    "MediaInfoResolution": "Resolution",
+    "MediaInfoAnamorphic": "Anamorphic",
+    "MediaInfoInterlaced": "Interlaced",
+    "MediaInfoFramerate": "Framerate",
+    "MediaInfoStreamTypeAudio": "Audio",
+    "MediaInfoStreamTypeData": "Data",
+    "MediaInfoStreamTypeVideo": "Video",
+    "MediaInfoStreamTypeSubtitle": "Subtitle",
+    "MediaInfoStreamTypeEmbeddedImage": "Embedded Image",
+    "MediaInfoRefFrames": "Ref frames",
+    "TabPlayback": "Playback",
+    "TabNotifications": "Notifications",
+    "TabExpert": "Expert",
+    "HeaderSelectCustomIntrosPath": "Select Custom Intros Path",
+    "HeaderRateAndReview": "Rate and Review",
+    "HeaderThankYou": "Thank You",
+    "MessageThankYouForYourReview": "Thank you for your review.",
+    "LabelYourRating": "Your rating:",
+    "LabelFullReview": "Full review:",
+    "LabelShortRatingDescription": "Short rating summary:",
+    "OptionIRecommendThisItem": "I recommend this item",
+    "WebClientTourContent": "View your recently added media, next episodes, and more. The green circles indicate how many unplayed items you have.",
+    "WebClientTourMovies": "Play movies, trailers and more from any device with a web browser",
+    "WebClientTourMouseOver": "Hold the mouse over any poster for quick access to important information",
+    "WebClientTourTapHold": "Tap and hold or right click any poster for a context menu",
+    "WebClientTourMetadataManager": "Click edit to open the metadata manager",
+    "WebClientTourPlaylists": "Easily create playlists and instant mixes, and play them on any device",
+    "WebClientTourCollections": "Create movie collections to group box sets together",
+    "WebClientTourUserPreferences1": "User preferences allow you to customize the way your library is presented in all of your Media Browser apps",
+    "WebClientTourUserPreferences2": "Configure your audio and subtitle language settings once, for every Media Browser app",
+    "WebClientTourUserPreferences3": "Design the web client home page to your liking",
+    "WebClientTourUserPreferences4": "Configure backdrops, theme songs and external players",
+    "WebClientTourMobile1": "The web client works great on smartphones and tablets...",
+    "WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
+    "WebClientTourMySync": "Sync your personal media to your devices for offline viewing.",
+    "MessageEnjoyYourStay": "Enjoy your stay",
+    "DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+    "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
+    "DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
+    "DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
+    "DashboardTourChapters": "Enable chapter image generation for your videos for a more pleasing presentation while viewing.",
+    "DashboardTourSubtitles": "Automatically download subtitles for your videos in any language.",
+    "DashboardTourPlugins": "Install plugins such as internet video channels, live tv, metadata scanners, and more.",
+    "DashboardTourNotifications": "Automatically send notifications of server events to your mobile device, email and more.",
+    "DashboardTourScheduledTasks": "Easily manage long running operations with scheduled tasks. Decide when they run, and how often.",
+    "DashboardTourMobile": "The Media Browser dashboard works great on smartphones and tablets. Manage your server from the palm of your hand anytime, anywhere.",
+    "DashboardTourSync": "Sync your personal media to your devices for offline viewing.",
+    "MessageRefreshQueued": "Refresh queued",
+    "TabDevices": "Devices",
+    "TabExtras": "Extras",
+    "DeviceLastUsedByUserName": "Last used by {0}",
+    "HeaderDeleteDevice": "Delete Device",
+    "DeleteDeviceConfirmation": "Are you sure you wish to delete this device? It will reappear the next time a user signs in with it.",
+    "LabelEnableCameraUploadFor": "Enable camera upload for:",
+    "HeaderSelectUploadPath": "Select Upload Path",
+    "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Media Browser.",
+    "ErrorMessageStartHourGreaterThanEnd": "End time must be greater than the start time.",
+    "ButtonLibraryAccess": "Library access",
+    "ButtonParentalControl": "Parental control",
+    "HeaderInvitationSent": "Invitation Sent",
+    "MessageInvitationSentToUser": "An email has been sent to {0}, inviting them to accept your sharing invitation.",
+    "MessageInvitationSentToNewUser": "An email has been sent to {0} inviting them to sign up with Media Browser.",
+    "HeaderConnectionFailure": "Connection Failure",
+    "MessageUnableToConnectToServer": "We're unable to connect to the selected server right now. Please ensure it is running and try again.",
+    "ButtonSelectServer": "Select server",
+    "MessagePluginConfigurationRequiresLocalAccess": "To configure this plugin please sign in to your local server directly.",
+    "MessageLoggedOutParentalControl": "Access is currently restricted. Please try again later.",
+    "DefaultErrorMessage": "There was an error processing the request. Please try again later.",
+    "ButtonAccept": "Accept",
+    "ButtonReject": "Reject",
+    "HeaderForgotPassword": "Forgot Password",
+    "MessageContactAdminToResetPassword": "Please contact your system administrator to reset your password.",
+    "MessageForgotPasswordInNetworkRequired": "Please try again within your home network to initiate the password reset process.",
+    "MessageForgotPasswordFileCreated": "The following file has been created on your server and contains instructions on how to proceed:",
+    "MessageForgotPasswordFileExpiration": "The reset pin will expire at {0}.",
+    "MessageInvalidForgotPasswordPin": "An invalid or expired pin was entered. Please try again.",
+    "MessagePasswordResetForUsers": "Passwords have been removed for the following users:",
+    "HeaderInviteGuest": "Invite Guest",
+    "ButtonLinkMyMediaBrowserAccount": "Link my account now",
+    "MessageConnectAccountRequiredToInviteGuest": "In order to invite guests you need to first link your Media Browser account to this server.",
+    "ButtonSync": "Sync",
+    "SyncMedia": "Sync Media",
+    "HeaderCancelSyncJob": "Cancel Sync",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
+    "TabSync": "Sync",
+    "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
+    "MessageSyncJobCreated": "Sync job created.",
+    "LabelSyncTo": "Sync to:",
+    "LabelSyncJobName": "Sync job name:",
+    "LabelQuality": "Quality:",
+    "HeaderSettings": "Settings",
+    "OptionAutomaticallySyncNewContent": "Automatically sync new content",
+    "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
+    "OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
+    "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
+    "LabelItemLimit": "Item limit:",
+    "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
+    "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
+    "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
+    "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders.",
+    "SyncJobItemStatusQueued": "Queued",
+    "SyncJobItemStatusConverting": "Converting",
+    "SyncJobItemStatusTransferring": "Transferring",
+    "SyncJobItemStatusSynced": "Synced",
+    "SyncJobItemStatusFailed": "Failed",
+    "SyncJobItemStatusRemovedFromDevice": "Removed from device",
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
+}
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
index c8e0064afa..e6c944d37f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Grazie. La vostra chiave supporter \u00e8 stato aggiornato.",
     "MessageKeyRemoved": "Grazie. La vostra chiave supporter \u00e8 stata rimossa.",
     "ErrorLaunchingChromecast": "Si \u00e8 verificato un errore all'avvio di chromecast. Assicurati che il tuo dispositivo sia connesso alla rete wireless.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Tempo limite: 1 ora",
+    "ValueTimeLimitMultiHour": "Tempo limite: {0} ore",
+    "HeaderUsers": "Utenti",
+    "PluginCategoryGeneral": "Generale",
+    "PluginCategoryContentProvider": "Fornitori di contenuti",
+    "PluginCategoryScreenSaver": "Salva schermo",
+    "PluginCategoryTheme": "Temi",
+    "PluginCategorySync": "Sincr.",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifiche",
+    "PluginCategoryMetadata": "Metadati",
+    "PluginCategoryLiveTV": "TV in diretta",
+    "PluginCategoryChannel": "Canali",
     "HeaderSearch": "Ricerca",
     "ValueDateCreated": "Data di creazione {0}",
     "LabelArtist": "Artista",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Aggiungi alla collezione",
     "HeaderSelectCertificatePath": "Seleziona il percorso del Certificato",
     "ConfirmMessageScheduledTaskButton": "L'operazione viene normalmente eseguita come operazione pianificata. Pu\u00f2 anche essere avviata manualmente da qui. Per configurare le operazioni pianificate, vedi:",
-    "HeaderSupporterBenefit": "La sottoscrizione Supporter concede dei benefici come: l'accesso a plug-in premium, contenuti dei canali internet, e altro. {0}Scopri di pi\u00f9{1}",
+    "HeaderSupporterBenefit": "L'iscrizione come supporter da benefici addizionali, come l'accesso alla sincronizzazione, i plugin premium, canali con contenuto internet, e altro. {0}Scopri di pi\u00f9{1}.",
     "LabelSyncNoTargetsHelp": "Sembra che al momento non avete applicazioni che supportano la sincronizzazione.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Benvenuti nel Dashboard di Media Browser",
     "HeaderWelcomeToMediaBrowserWebClient": "Benvenuti nel Media Browser Web client",
     "ButtonTakeTheTour": "Fai il tour",
     "HeaderWelcomeBack": "Ben tornato!",
+    "TitleSync": "Sincronizza",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Fai un tour per vedere cosa \u00e8 cambiato",
     "MessageNoSyncJobsFound": "Nessuna sincronizzazione pianificata. Creane una utilizzando i pulsanti sull'interfaccia web",
     "HeaderLibraryAccess": "Accesso libreria",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installato",
     "LabelNumberReviews": "{0} Recensioni",
     "LabelFree": "Gratis",
+    "HeaderPlaybackError": "Errore di riproduzione",
+    "MessagePlaybackErrorNotAllowed": "Al momento non sei autorizzato a riprodurre questo contenuto. Per favore contatta l'amministratore del sistema per ulteriori dettagli",
+    "MessagePlaybackErrorNoCompatibleStream": "Nessuna trasmissione compatibile \u00e8 al momento disponibile. Per favore riprova in seguito",
+    "MessagePlaybackErrorRateLimitExceeded": "La tua quota di riproduzione \u00e8 stata raggiunta. Per favore contatta l'amministratore del sistema per ulteriori dettagli",
     "HeaderSelectAudio": "Seleziona audio",
     "HeaderSelectSubtitles": "Seleziona sottotitoli",
     "ButtonMarkForRemoval": "Rimuovi dal dispositivo",
     "ButtonUnmarkForRemoval": "Annulla rimozione dal dispositivo",
-    "LabelSyncQualityHelp": "Utilizzare alta qualit\u00e0 per la massima supportata qualit\u00e0 dal dispositivo. Media e bassa qualit\u00e0 riduce il bitrate consentito. Original sincronizzer\u00e0 il file originale, indipendentemente dal fatto che il dispositivo \u00e8 in grado di riprodurre o meno.",
     "LabelDefaultStream": "(Predefinito)",
     "LabelForcedStream": "(forzato)",
     "LabelDefaultForcedStream": "(Predefinito\/Forzato)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Debuttato {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studi: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Speciali - {0}",
     "LabelLimit": "Limite:",
     "ValueLinks": "Collegamenti: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sinc.",
     "SyncMedia": "Sync media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Sei sicuro di voler annullare questo lavoro di sincronizzazione?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sinc",
     "MessagePleaseSelectDeviceToSyncTo": "Selezionare un dispositivo per la sincronizzazione",
     "MessageSyncJobCreated": "Attivit\u00e0 di Sincronizz. Creata",
     "LabelSyncTo": "Sincronizza su:",
     "LabelSyncJobName": "Nome Attivit\u00e0 di Sincroniz.:",
     "LabelQuality": "Qualit\u00e0:",
-    "OptionOriginal": "Originale",
-    "OptionHigh": "Alto",
-    "OptionMedium": "Medio",
-    "OptionLow": "Basso",
     "HeaderSettings": "Configurazione",
     "OptionAutomaticallySyncNewContent": "Sincronizza automaticamente nuovi contenuti",
     "OptionAutomaticallySyncNewContentHelp": "Nuovi contenuti aggiunti a questa categoria viene sincronizzata automaticamente al dispositivo.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Sincronizzato",
     "SyncJobItemStatusFailed": "Fallito",
     "SyncJobItemStatusRemovedFromDevice": "Rimosso dal dispositivo",
-    "SyncJobItemStatusCancelled": "Cancellato"
+    "SyncJobItemStatusCancelled": "Cancellato",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
index 09045be9bd..ffba5e5ab9 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default/Forced)",
@@ -568,6 +591,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -705,17 +729,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -732,5 +752,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
index 70a5d9cf42..ba0f39c864 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456\u04a3\u0456\u0437 \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0434\u044b.",
     "MessageKeyRemoved": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456\u04a3\u0456\u0437 \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0434\u044b.",
     "ErrorLaunchingChromecast": "Chromecast \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u04a3\u044b\u0437 \u0441\u044b\u043c\u0441\u044b\u0437 \u0436\u0435\u043b\u0456\u0433\u0435 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u044b\u043d\u0430 \u043a\u04e9\u0437 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u04a3\u0456\u0437.",
+    "MessageErrorLoadingSupporterInfo": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u0430\u049b\u043f\u0430\u0440\u0430\u0442\u044b\u043d \u0436\u04af\u043a\u0442\u0435\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u049b\u0430\u0442\u0435 \u043e\u0440\u044b\u043d \u0430\u043b\u0434\u044b. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
+    "MessageLinkYourSupporterKey": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0431\u0430\u0493\u0434\u0430\u0440\u043b\u0430\u043c\u0430\u043b\u0430\u0440\u0493\u0430 \u0442\u0435\u0433\u0456\u043d \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u0434\u044b \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u0443 \u04af\u0448\u0456\u043d Media Browser Connect  {0} \u043c\u04af\u0448\u0435\u0441\u0456\u043d\u0435 \u0434\u0435\u0439\u0456\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u044b\u04a3\u044b\u0437.",
+    "HeaderConfirmRemoveUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u0430\u043b\u0430\u0441\u0442\u0430\u0443",
+    "MessageSwipeDownOnRemoteControl": "\u049a\u0430\u0448\u044b\u049b\u0442\u0430\u043d \u0431\u0430\u0441\u049b\u0430\u0440\u0443\u0493\u0430 \u049b\u043e\u0448 \u043a\u0435\u043b\u0434\u0456\u04a3\u0456\u0437. \u049a\u0430\u0439\u0434\u0430\u043d \u043a\u0435\u043b\u0441\u0435\u04a3\u0456\u0437, \u0441\u043e\u0493\u0430\u043d \u049b\u0430\u0439\u0442\u0430 \u0431\u0430\u0440\u0443 \u04af\u0448\u0456\u043d \u043e\u0441\u044b \u044d\u043a\u0440\u0430\u043d\u0434\u044b\u04a3 \u043a\u0435\u0437 \u043a\u0435\u043b\u0433\u0435\u043d \u0436\u0435\u0440\u0456\u043d\u0434\u0435 \u0442\u04e9\u043c\u0435\u043d \u049b\u0430\u0440\u0430\u0439 \u0441\u0438\u043f\u0430\u043f \u04e9\u0442\u0456\u04a3\u0456\u0437.",
+    "MessageConfirmRemoveConnectSupporter": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u0434\u0430\u043d \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b\u043d\u044b\u04a3 \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u0430\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b\u0442\u0430\u0440\u044b\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
+    "ValueTimeLimitSingleHour": "\u0423\u0430\u049b\u044b\u0442 \u0448\u0435\u0433\u0456: 1 \u0441\u0430\u0493\u0430\u0442",
+    "ValueTimeLimitMultiHour": "\u0423\u0430\u049b\u044b\u0442 \u0448\u0435\u0433\u0456: {0} \u0441\u0430\u0493\u0430\u0442",
+    "HeaderUsers": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440",
+    "PluginCategoryGeneral": "\u0416\u0430\u043b\u043f\u044b",
+    "PluginCategoryContentProvider": "\u041c\u0430\u0437\u043c\u04b1\u043d \u0436\u0435\u0442\u043a\u0456\u0437\u0443\u0448\u0456\u043b\u0435\u0440",
+    "PluginCategoryScreenSaver": "\u042d\u043a\u0440\u0430\u043d \u049b\u043e\u0440\u0493\u0430\u0443\u044b\u0448\u0442\u0430\u0440",
+    "PluginCategoryTheme": "\u0422\u0430\u049b\u044b\u0440\u044b\u043f\u0442\u0430\u0440",
+    "PluginCategorySync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
+    "PluginCategorySocialIntegration": "\u04d8\u043b\u0435\u0443\u043c\u0435\u0442 \u0436\u0435\u043b\u0456\u043b\u0435\u0440\u0456",
+    "PluginCategoryNotifications": "\u0425\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443\u043b\u0430\u0440",
+    "PluginCategoryMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440",
+    "PluginCategoryLiveTV": "\u042d\u0444\u0438\u0440\u043b\u0456\u043a \u0422\u0414",
+    "PluginCategoryChannel": "\u0410\u0440\u043d\u0430\u043b\u0430\u0440",
     "HeaderSearch": "\u0406\u0437\u0434\u0435\u0443",
     "ValueDateCreated": "\u0416\u0430\u0441\u0430\u043b\u0493\u0430\u043d \u043a\u04af\u043d\u0456: {0}",
     "LabelArtist": "\u041e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u049b\u0430 \u04af\u0441\u0442\u0435\u0443",
     "HeaderSelectCertificatePath": "\u041a\u0443\u04d9\u043b\u0456\u043a \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
     "ConfirmMessageScheduledTaskButton": "\u0411\u04b1\u043b \u04d9\u0440\u0435\u043a\u0435\u0442 \u04d9\u0434\u0435\u0442\u0442\u0435 \u0436\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0493\u0430\u043d \u0442\u0430\u043f\u0441\u044b\u0440\u043c\u0430 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0436\u04b1\u043c\u044b\u0441 \u0456\u0441\u0442\u0435\u0439\u0434\u0456. \u041e\u0441\u044b\u043d\u044b \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b \u0431\u04b1\u043b \u0436\u0435\u0440\u0434\u0435 \u049b\u043e\u043b\u043c\u0435\u043d \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443\u0493\u0430 \u0431\u043e\u043b\u0430\u0434\u044b. \u0416\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0493\u0430\u043d \u0442\u0430\u043f\u0441\u044b\u0440\u043c\u0430\u043d\u044b \u0442\u0435\u04a3\u0448\u0435\u0443 \u04af\u0448\u0456\u043d, \u049b\u0430\u0440\u0430\u04a3\u044b\u0437:",
-    "HeaderSupporterBenefit": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043c\u04af\u0448\u0435\u043b\u0456\u043a \u0441\u044b\u0439\u0430\u049b\u044b\u043b\u044b \u043f\u043b\u0430\u0433\u0438\u043d, \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0430\u0440\u043d\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d\u044b \u0436\u04d9\u043d\u0435 \u0441\u043e\u043d\u0434\u0430\u0439 \u0441\u0438\u044f\u049b\u0442\u044b\u043b\u0430\u0440\u0493\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u043c\u0435\u043d \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u0430\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b\u0442\u0430\u0440 \u0431\u0435\u0440\u0435\u0434\u0456. {0}\u041a\u04e9\u0431\u0456\u0440\u0435\u043a \u0431\u0456\u043b\u0443{1}.",
+    "HeaderSupporterBenefit": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043c\u04af\u0448\u0435\u043b\u0456\u043a \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u0430\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b\u0442\u0430\u0440\u0434\u044b (\u043c\u044b\u0441\u0430\u043b\u044b, \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443\u0433\u0435 \u049b\u0430\u0442\u044b\u043d\u0430\u0443, \u0441\u044b\u0439\u0430\u049b\u044b\u043b\u044b\u049b \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440, \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0430\u0440\u043d\u0430\u0441\u044b\u043d\u044b\u04a3 \u043c\u0430\u0437\u043c\u04b1\u043d\u044b \u0436\u0430\u04a3\u0435 \u0442.\u0431.) \u049b\u0430\u043c\u0442\u0430\u043c\u0430\u0441\u044b\u0437 \u0435\u0442\u0435\u0434\u0456. {0}\u041a\u04e9\u0431\u0456\u0440\u0435\u043a \u0431\u0456\u043b\u0443{1}.",
     "LabelSyncNoTargetsHelp": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443\u0434\u0456 \u049b\u043e\u043b\u0434\u0430\u0439\u0442\u044b\u043d  \u049b\u043e\u043b\u0434\u0430\u043d\u0431\u0430 \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0434\u044b.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Media Browser \u0431\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u0441\u044b\u043d\u0430 \u049b\u043e\u0448 \u043a\u0435\u043b\u0434\u0456\u04a3\u0456\u0437!",
     "HeaderWelcomeToMediaBrowserWebClient": "Media Browser \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0456\u043d\u0435 \u049b\u043e\u0448 \u043a\u0435\u043b\u0434\u0456\u04a3\u0456\u0437!",
     "ButtonTakeTheTour": "\u0410\u0440\u0430\u043b\u0430\u043f \u0448\u044b\u0493\u044b\u04a3\u044b\u0437",
     "HeaderWelcomeBack": "\u049a\u0430\u0439\u0442\u0430 \u043a\u0435\u043b\u0443\u0456\u04a3\u0456\u0437\u0431\u0435\u043d!",
+    "TitleSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
+    "TitlePlugins": "\u041f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440",
     "ButtonTakeTheTourToSeeWhatsNew": "\u0411\u043e\u043b\u0493\u0430\u043d \u0436\u0430\u04a3\u0430\u043b\u044b\u049b\u0442\u0430\u0440\u043c\u0435\u043d \u0442\u0430\u043d\u044b\u0441\u0443",
     "MessageNoSyncJobsFound": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b \u0442\u0430\u0431\u044b\u043b\u043c\u0430\u0434\u044b. \u0412\u0435\u0431-\u0442\u0456\u043b\u0434\u0435\u0441\u0443\u0434\u0435 \u0442\u0430\u0431\u044b\u043b\u0430\u0442\u044b\u043d \u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u043a\u0442\u0435\u0440\u0456\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043f \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u0442\u0430\u0440\u044b\u043d \u0436\u0430\u0441\u0430\u04a3\u044b\u0437.",
     "HeaderLibraryAccess": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430\u0493\u0430 \u049b\u0430\u0442\u044b\u043d\u0430\u0443",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
     "LabelNumberReviews": "{0} \u043f\u0456\u043a\u0456\u0440",
     "LabelFree": "\u0422\u0435\u0433\u0456\u043d",
+    "HeaderPlaybackError": "\u041e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0442\u0435\u0441\u0456",
+    "MessagePlaybackErrorNotAllowed": "\u041e\u0441\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u0430\u0493\u044b\u043c\u0434\u0430 \u0441\u0456\u0437\u0433\u0435 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0456\u043b\u043c\u0435\u0433\u0435\u043d. \u041c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
+    "MessagePlaybackErrorNoCompatibleStream": "\u0410\u0493\u044b\u043c\u0434\u0430 \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0441\u044b\u0439\u044b\u0441\u044b\u043c\u0434\u044b \u0430\u0493\u044b\u043d\u0434\u0430\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0443\u043b\u044b \u0435\u043c\u0435\u0441. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u043a\u0435\u0439\u0456\u043d \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
+    "MessagePlaybackErrorRateLimitExceeded": "\u041e\u0439\u043d\u0430\u0442\u0443 \u049b\u0430\u0440\u049b\u044b\u043d\u044b\u04a3\u044b\u0437 \u0448\u0435\u043a\u0442\u0435\u043d \u0430\u0441\u044b\u043f \u043a\u0435\u0442\u043a\u0435\u043d. \u041c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
     "HeaderSelectAudio": "\u0414\u044b\u0431\u044b\u0441 \u0442\u0430\u04a3\u0434\u0430\u0443",
     "HeaderSelectSubtitles": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 \u0442\u0430\u04a3\u0434\u0430\u0443",
     "ButtonMarkForRemoval": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443",
     "ButtonUnmarkForRemoval": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443\u0434\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
-    "LabelSyncQualityHelp": "\u0416\u043e\u0493\u0430\u0440\u044b \u0441\u0430\u043f\u0430 - \u049b\u04b1\u0440-\u043d\u044b\u04a3 \u0431\u0430\u0440\u044b\u043d\u0448\u0430 \u049b\u043e\u043b\u0434\u0430\u0443 \u0441\u0430\u043f\u0430\u0441\u044b \u04af\u0448\u0456\u043d. \u041e\u0440\u0442\u0430 \u0436\u04d9\u043d\u0435 \u0442\u04e9\u043c\u0435\u043d - \u04b1\u0439\u0493\u0430\u0440\u044b\u043d\u0434\u044b \u049b\u0430\u0440\u049b\u044b\u043d\u0434\u044b \u0430\u0437\u0430\u0439\u0442\u0430\u0434\u044b. \u0422\u04af\u043f\u043d\u04b1\u0441\u049b\u0430\u043b\u044b - \u049b\u04b1\u0440-\u043d\u044b\u04a3 \u0431\u0430\u0441\u0442\u0430\u043f\u049b\u044b \u0444\u0430\u0439\u043b \u04af\u043d\u0434-\u0434\u0456.",
     "LabelDefaultStream": "(\u04d8\u0434\u0435\u043f\u043a\u0456)",
     "LabelForcedStream": "(\u041c\u04d9\u0436\u0431\u04af\u0440\u043b\u0456)",
     "LabelDefaultForcedStream": "(\u04d8\u0434\u0435\u043f\u043a\u0456\/\u041c\u04d9\u0436\u0431\u04af\u0440\u043b\u0456)",
@@ -208,7 +231,7 @@
     "StatusFailed": "\u0421\u04d9\u0442\u0441\u0456\u0437",
     "StatusSuccess": "\u0421\u04d9\u0442\u0442\u0456\u043b\u0456\u043a",
     "MessageFileWillBeDeleted": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0444\u0430\u0439\u043b \u0436\u043e\u0439\u044b\u043b\u0430\u0434\u044b:",
-    "MessageSureYouWishToProceed": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
+    "MessageSureYouWishToProceed": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043a\u0456\u0440\u0456\u0441\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
     "MessageDuplicatesWillBeDeleted": "\u049a\u043e\u0441\u044b\u043c\u0448\u0430 \u0440\u0435\u0442\u0456\u043d\u0434\u0435, \u043a\u0435\u043b\u0435\u0441\u0456 \u0442\u0435\u043b\u043d\u04b1\u0441\u049b\u0430\u043b\u0430\u0440 \u0436\u043e\u0439\u044b\u043b\u0430\u0434\u044b:",
     "MessageFollowingFileWillBeMovedFrom": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0444\u0430\u0439\u043b \u0436\u044b\u043b\u0436\u044b\u0442\u044b\u043b\u0430\u0434\u044b, \u043c\u044b\u043d\u0430\u0434\u0430\u043d:",
     "MessageDestinationTo": "\u043c\u044b\u043d\u0430\u0493\u0430\u043d:",
@@ -470,8 +493,8 @@
     "HeaderMediaLocations": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u043b\u0430\u0440\u044b",
     "LabelContentTypeValue": "\u041c\u0430\u0437\u043c\u04b1\u043d \u0442\u04af\u0440\u0456: {0}",
     "LabelPathSubstitutionHelp": "\u041c\u0456\u043d\u0434\u0435\u0442\u0442\u0456 \u0435\u043c\u0435\u0441: \u0416\u043e\u043b \u0430\u043b\u043c\u0430\u0441\u0442\u044b\u0440\u0443 \u0430\u0440\u049b\u044b\u043b\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0435\u0433\u0456 \u0436\u043e\u043b\u0434\u0430\u0440\u0434\u044b \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0443 \u043c\u04af\u043c\u043a\u0456\u043d \u0436\u0435\u043b\u0456\u043b\u0456\u043a \u049b\u043e\u0440 \u043a\u04e9\u0437\u0434\u0435\u0440\u0456\u043c\u0435\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
-    "FolderTypeUnset": "\u0422\u0430\u0493\u0430\u0439\u044b\u043d\u0434\u0430\u043b\u043c\u0430\u0493\u0430\u043d (\u04d9\u0440\u0442\u04af\u0440\u043b\u0456 \u043c\u0430\u0437\u043c\u04b1\u043d)",
-    "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
+    "FolderTypeUnset": "\u0422\u0430\u0493\u0430\u0439\u044b\u043d\u0434\u0430\u043b\u043c\u0430\u0493\u0430\u043d (\u0430\u0440\u0430\u043b\u0430\u0441 \u043c\u0430\u0437\u043c\u04b1\u043d)",
+    "FolderTypeMovies": "\u041a\u0438\u043d\u043e",
     "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
     "FolderTypeAdultVideos": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0456\u043a \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
     "FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440",
@@ -502,7 +525,7 @@
     "ValuePriceUSD": "\u0411\u0430\u0493\u0430\u0441\u044b: {0} USD",
     "MessageFeatureIncludedWithSupporter": "\u041e\u0441\u044b \u0435\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a \u04af\u0448\u0456\u043d \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0435\u043d\u0441\u0456\u0437, \u0436\u04d9\u043d\u0435 \u043e\u043d\u044b \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043c\u04af\u0448\u0435\u043b\u0456\u0433\u0456 \u0430\u0440\u049b\u044b\u043b\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0434\u044b \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0430 \u0430\u043b\u0430\u0441\u044b\u0437.",
     "MessageChangeRecurringPlanConfirm": "\u041e\u0441\u044b \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043d\u044b \u0430\u044f\u049b\u0442\u0430\u0493\u0430\u043d\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d PayPal \u0435\u0441\u0435\u043f \u0448\u043e\u0442\u044b\u04a3\u044b\u0437 \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u043b\u0434\u044b\u04a3\u0493\u044b \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u043c\u0430 \u049b\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0434\u044b\u049b\u0442\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443\u044b\u04a3\u044b\u0437 \u049b\u0430\u0436\u0435\u0442. Media Browser \u0436\u043e\u0431\u0430\u0441\u044b\u043d \u0436\u0430\u049b\u0442\u0430\u0443\u044b\u04a3\u044b\u0437\u0493\u0430 \u0430\u043b\u0493\u044b\u0441 \u0430\u0439\u0442\u0430\u043c\u044b\u0437!",
-    "MessageSupporterMembershipExpiredOn": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043c\u04af\u0448\u0435\u043b\u0456\u0433\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 {0} \u0431\u0456\u0442\u0442\u0456.",
+    "MessageSupporterMembershipExpiredOn": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043c\u04af\u0448\u0435\u043b\u0456\u0433\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 {0} \u0430\u044f\u049b\u0442\u0430\u043b\u0493\u0430\u043d.",
     "MessageYouHaveALifetimeMembership": "\u0492\u04b1\u043c\u044b\u0440\u043b\u044b\u049b \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043c\u04af\u0448\u0435\u043b\u0456\u0433\u0456\u043d\u0435 \u0442\u0438\u0435\u0441\u043b\u0456\u0441\u0456\u0437. \u0422\u04e9\u043c\u0435\u043d\u0434\u0435\u0433\u0456 \u043d\u04b1\u0441\u049b\u0430\u043b\u0430\u0440\u0434\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043f \u0431\u0456\u0440 \u0436\u043e\u043b\u0493\u044b \u043d\u0435\u043c\u0435\u0441\u0435 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u043c\u0430 \u043d\u0435\u0433\u0456\u0437\u0456\u043d\u0434\u0435 \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u049b\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0434\u044b\u049b\u0442\u0430\u0440\u0434\u044b \u049b\u0430\u043c\u0442\u0430\u043c\u0430\u0441\u044b\u0437 \u0435\u0442\u0443 \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u0433\u0456\u04a3\u0456\u0437 \u0431\u0430\u0440. Media Browser \u0436\u043e\u0431\u0430\u0441\u044b\u043d \u0436\u0430\u049b\u0442\u0430\u0443\u044b\u04a3\u044b\u0437\u0493\u0430 \u0430\u043b\u0493\u044b\u0441 \u0430\u0439\u0442\u0430\u043c\u044b\u0437!",
     "MessageYouHaveAnActiveRecurringMembership": "\u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456 {0} \u043c\u04af\u0448\u0435\u043b\u0456\u0433\u0456\u043d\u0435 \u0442\u0438\u0435\u0441\u043b\u0456\u0441\u0456\u0437. \u0422\u04e9\u043c\u0435\u043d\u0434\u0435\u0433\u0456 \u043d\u04b1\u0441\u049b\u0430\u043b\u0430\u0440\u0434\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043f \u0436\u043e\u0441\u043f\u0430\u0440\u044b\u04a3\u044b\u0437\u0434\u044b \u043a\u04e9\u0442\u0435\u0440\u0443 \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u0433\u0456\u04a3\u0456\u0437 \u0431\u0430\u0440",
     "ButtonDelete": "\u0416\u043e\u044e",
@@ -559,6 +582,7 @@
     "ValuePremieres": "\u041f\u0440\u0435\u043c\u044c\u0435\u0440\u0430\u0441\u044b {0}",
     "ValueStudio": "\u0421\u0442\u0443\u0434\u0438\u044f\u0441\u044b: {0}",
     "ValueStudios": "\u0421\u0442\u0443\u0434\u0438\u044f\u043b\u0430\u0440\u044b: {0}",
+    "ValueStatus": "\u041a\u04af\u0439\u0456: {0}",
     "ValueSpecialEpisodeName": "\u0410\u0440\u043d\u0430\u0439\u044b - {0}",
     "LabelLimit": "\u0428\u0435\u0433\u0456:",
     "ValueLinks": "\u0421\u0456\u043b\u0442\u0435\u043c\u0435\u043b\u0435\u0440: {0}",
@@ -685,9 +709,9 @@
     "HeaderForgotPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u04b1\u043c\u044b\u0442\u044b\u04a3\u044b\u0437 \u0431\u0430?",
     "MessageContactAdminToResetPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0456\u04a3\u0456\u0437\u0434\u0456 \u044b\u0441\u044b\u0440\u0443 \u04af\u0448\u0456\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u04d9\u043a\u0456\u043c\u0448\u0456\u04a3\u0456\u0437\u0433\u0435 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u044b\u04a3\u044b\u0437.",
     "MessageForgotPasswordInNetworkRequired": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u044b\u0441\u044b\u0440\u0443 \u04af\u0434\u0435\u0440\u0456\u0441\u0456 \u04af\u0448\u0456\u043d \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u04af\u0439\u043b\u0456\u043a \u0436\u0435\u043b\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u0456\u0448\u0456\u043d\u0434\u0435 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
-    "MessageForgotPasswordFileCreated": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0444\u0430\u0439\u043b \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u04a3\u0456\u0437\u0434\u0435 \u0436\u0430\u0441\u0430\u043b\u0434\u044b \u0436\u04d9\u043d\u0435 \u049b\u0430\u043b\u0430\u0439 \u0436\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u0442\u0443\u0440\u0430\u043b\u044b \u043d\u04b1\u0441\u049b\u0430\u0443\u043b\u0430\u0440 \u0456\u0448\u0456\u043d\u0434\u0435 \u0431\u0430\u0440:",
+    "MessageForgotPasswordFileCreated": "\u041a\u0435\u043b\u0435\u0441\u0456 \u0444\u0430\u0439\u043b \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u04a3\u0456\u0437\u0434\u0435 \u0436\u0430\u0441\u0430\u043b\u0434\u044b \u0436\u04d9\u043d\u0435 \u049b\u0430\u043b\u0430\u0439 \u043a\u0456\u0440\u0456\u0441\u0443 \u0442\u0443\u0440\u0430\u043b\u044b \u043d\u04b1\u0441\u049b\u0430\u0443\u043b\u0430\u0440 \u0456\u0448\u0456\u043d\u0434\u0435 \u0431\u0430\u0440:",
     "MessageForgotPasswordFileExpiration": "PIN \u044b\u0441\u044b\u0440\u0443 \u043c\u0435\u0437\u0433\u0456\u043b\u0456 {0} \u0431\u0456\u0442\u0435\u0434\u0456.",
-    "MessageInvalidForgotPasswordPin": "\u0416\u0430\u0440\u0430\u043c\u0441\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 \u0431\u0456\u0442\u043a\u0435\u043d PIN \u0435\u043d\u0433\u0456\u0437\u0456\u043b\u0434\u0456. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
+    "MessageInvalidForgotPasswordPin": "\u0416\u0430\u0440\u0430\u043c\u0441\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 \u0430\u044f\u049b\u0442\u0430\u043b\u0493\u0430\u043d PIN \u0435\u043d\u0433\u0456\u0437\u0456\u043b\u0434\u0456. \u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0456 \u049b\u0430\u0439\u0442\u0430\u043b\u0430\u04a3\u044b\u0437.",
     "MessagePasswordResetForUsers": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0435\u0440 \u043a\u0435\u043b\u0435\u0441\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440 \u04af\u0448\u0456\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0434\u044b:",
     "HeaderInviteGuest": "\u049a\u043e\u043d\u0430\u049b\u0442\u044b \u0448\u0430\u049b\u044b\u0440\u0443",
     "ButtonLinkMyMediaBrowserAccount": "\u0422\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u043c\u0434\u0456 \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443",
@@ -695,17 +719,13 @@
     "ButtonSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
     "SyncMedia": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
     "HeaderCancelSyncJob": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443\u0434\u0456 \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
-    "CancelSyncJobConfirmation": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u0442\u044b \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
+    "CancelSyncJobConfirmation": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u0431\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443 \u043a\u0435\u043b\u0435\u0441\u0456 \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0434\u0435\u0440\u0456\u0441\u0456\u043d\u0434\u0435 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u043e\u044e\u0493\u0430 \u04d9\u043a\u0435\u043b\u0435\u0434\u0456. \u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043a\u0456\u0440\u0456\u0441\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
     "TabSync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
     "MessagePleaseSelectDeviceToSyncTo": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u043b\u0435\u0442\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043d\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
     "MessageSyncJobCreated": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b \u0436\u0430\u0441\u0430\u043b\u0434\u044b.",
     "LabelSyncTo": "\u041e\u0441\u044b\u043c\u0435\u043d \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443:",
     "LabelSyncJobName": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b\u043d\u044b\u04a3 \u0430\u0442\u044b:",
     "LabelQuality": "\u0421\u0430\u043f\u0430\u0441\u044b:",
-    "OptionOriginal": "\u0422\u04af\u043f\u043d\u04b1\u0441\u049b\u0430\u043b\u044b",
-    "OptionHigh": "\u0416\u043e\u0493\u0430\u0440\u044b",
-    "OptionMedium": "\u041e\u0440\u0442\u0430\u0448\u0430",
-    "OptionLow": "\u0422\u04e9\u043c\u0435\u043d",
     "HeaderSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440",
     "OptionAutomaticallySyncNewContent": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u04af\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
     "OptionAutomaticallySyncNewContentHelp": "\u041e\u0441\u044b \u0441\u0430\u043d\u0430\u0442\u049b\u0430 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u0436\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u049b\u04b1\u0440-\u043c\u0435\u043d \u04af\u043d\u0434-\u0434\u0456.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d",
     "SyncJobItemStatusFailed": "\u0421\u04d9\u0442\u0441\u0456\u0437",
     "SyncJobItemStatusRemovedFromDevice": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0493\u0430\u043d",
-    "SyncJobItemStatusCancelled": "\u0411\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b"
+    "SyncJobItemStatusCancelled": "\u0411\u043e\u043b\u0434\u044b\u0440\u044b\u043b\u043c\u0430\u0434\u044b",
+    "LabelProfile": "\u041f\u0440\u043e\u0444\u0430\u0439\u043b:",
+    "LabelBitrateMbps": "\u049a\u0430\u0440\u049b\u044b\u043d\u044b (\u041c\u0431\u0438\u0442\/\u0441):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
index 7061f87d78..801a3e8d30 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
index a8b645653a..c27cc7cf1e 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
@@ -6,20 +6,20 @@
     "Administrator": "Administrator",
     "Password": "Passord",
     "DeleteImage": "Slett bilde",
-    "MessageThankYouForSupporting": "Thank you for supporting Media Browser.",
-    "MessagePleaseSupportMediaBrowser": "Please support Media Browser.",
+    "MessageThankYouForSupporting": "Takk for at du st\u00f8tter Media Browser.",
+    "MessagePleaseSupportMediaBrowser": "Vennligst st\u00f8tt Media Browser.",
     "DeleteImageConfirmation": "Er du sikker p\u00e5 at du vil slette bildet?",
     "FileReadCancelled": "Lesing av filen kansellert.",
     "FileNotFound": "Fil ikke funnet",
     "FileReadError": "Feil oppstod i det filen ble lest",
     "DeleteUser": "Slett bruker",
     "DeleteUserConfirmation": "Er du sikker p\u00e5 at du vil slette denne brukeren?",
-    "PasswordResetHeader": "Reset Password",
-    "PasswordResetComplete": "Passordet har blitt resatt",
-    "PinCodeResetComplete": "The pin code has been reset.",
-    "PasswordResetConfirmation": "Er du sikker p\u00e5 at du vil resette passordet?",
-    "PinCodeResetConfirmation": "Are you sure you wish to reset the pin code?",
-    "HeaderPinCodeReset": "Reset Pin Code",
+    "PasswordResetHeader": "Tilbakestill passord",
+    "PasswordResetComplete": "Passordet har blitt tilbakestilt",
+    "PinCodeResetComplete": "PIN-koden har blitt tilbakestilt",
+    "PasswordResetConfirmation": "Er du sikker p\u00e5 at du vil tilbakestille passordet?",
+    "PinCodeResetConfirmation": "Er du sikker p\u00e5 at du vil tilbakestille PIN-koden?",
+    "HeaderPinCodeReset": "Tilbakestill PIN-kode",
     "PasswordSaved": "Passord lagret",
     "PasswordMatchError": "Passord og passord-verifiseringen m\u00e5 matche",
     "OptionRelease": "Offisiell utgivelse",
@@ -33,11 +33,29 @@
     "MessageKeyEmailedTo": "N\u00f8kkel sendt til {0}",
     "MessageKeysLinked": "N\u00f8kler lenket.",
     "HeaderConfirmation": "Bekreftelse",
-    "MessageKeyUpdated": "Takk. Din supporter n\u00f8kkel har blitt oppdatert.",
-    "MessageKeyRemoved": "Takk. Din supporter n\u00f8kkel har blitt fjernet.",
-    "ErrorLaunchingChromecast": "Det var en error ved \u00e5 starte Chromecast. Vennligst forsikre deg om at enheten har korrekt forbindelse mot ditt tr\u00e5dl\u00f8se nettverk.",
+    "MessageKeyUpdated": "Takk. Din supportern\u00f8kkel har blitt oppdatert.",
+    "MessageKeyRemoved": "Takk. Din supportern\u00f8kkel har blitt fjernet.",
+    "ErrorLaunchingChromecast": "Det var en feil ved start av Chromecast. Vennligst forsikre deg om at enheten har korrekt forbindelse til ditt tr\u00e5dl\u00f8se nettverk.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Brukere",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "S\u00f8k",
-    "ValueDateCreated": "Date created: {0}",
+    "ValueDateCreated": "Dato opprettet: {0}",
     "LabelArtist": "Artist",
     "LabelMovie": "Film",
     "LabelMusicVideo": "Musikk Video",
@@ -46,46 +64,48 @@
     "LabelStopping": "Stoppe",
     "LabelCancelled": "(kansellert)",
     "LabelFailed": "(Feilet)",
-    "ButtonHelp": "Help",
-    "ButtonSave": "lagre",
+    "ButtonHelp": "Hjelp",
+    "ButtonSave": "Lagre",
     "ButtonDownload": "Nedlasting",
-    "SyncJobStatusQueued": "Queued",
-    "SyncJobStatusConverting": "Converting",
-    "SyncJobStatusFailed": "Failed",
-    "SyncJobStatusCancelled": "Cancelled",
-    "SyncJobStatusCompleted": "Synced",
-    "SyncJobStatusReadyToTransfer": "Ready to Transfer",
-    "SyncJobStatusTransferring": "Transferring",
-    "SyncJobStatusCompletedWithError": "Synced with errors",
-    "SyncJobItemStatusReadyToTransfer": "Ready to Transfer",
-    "LabelCollection": "Collection",
-    "HeaderAddToCollection": "Legg Til I Samling",
-    "NewCollectionNameExample": "Eksempel: Star Wars Samling",
+    "SyncJobStatusQueued": "I k\u00f8",
+    "SyncJobStatusConverting": "Konverterer",
+    "SyncJobStatusFailed": "Feilet",
+    "SyncJobStatusCancelled": "Avbrutt",
+    "SyncJobStatusCompleted": "Synkronisert",
+    "SyncJobStatusReadyToTransfer": "Klar til overf\u00f8ring",
+    "SyncJobStatusTransferring": "Overf\u00f8rer",
+    "SyncJobStatusCompletedWithError": "Synkronisert med feil",
+    "SyncJobItemStatusReadyToTransfer": "Klar til overf\u00f8ring",
+    "LabelCollection": "Samling",
+    "HeaderAddToCollection": "Legg til i Samling",
+    "NewCollectionNameExample": "Eksempel: Star Wars-samling",
     "OptionSearchForInternetMetadata": "S\u00f8k p\u00e5 internet for artwork og metadata",
     "LabelSelectCollection": "Velg samling:",
-    "HeaderDevices": "Devices",
-    "ButtonScheduledTasks": "Scheduled tasks",
-    "MessageItemsAdded": "Items added",
-    "ButtonAddToCollection": "Add to collection",
-    "HeaderSelectCertificatePath": "Select Certificate Path",
-    "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
-    "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
+    "HeaderDevices": "Enheter",
+    "ButtonScheduledTasks": "Planlagte oppgaver",
+    "MessageItemsAdded": "Elementer lagt til",
+    "ButtonAddToCollection": "Legg til samling",
+    "HeaderSelectCertificatePath": "Velg sti for sertifikat:",
+    "ConfirmMessageScheduledTaskButton": "Dette kj\u00f8res vanligvis automatisk som en planlagt oppgave. Den kan ogs\u00e5 kj\u00f8res manuelt herfra. For \u00e5 konfigurere planlagte oppgaver, se:",
+    "HeaderSupporterBenefit": "St\u00f8ttemedlemskap gir ytterligere fordeler som for eksempel tilgang til synkronisering, premium plugins, internett-kanaler og mer. {0}L\u00e6r mer{1}.",
+    "LabelSyncNoTargetsHelp": "Det ser ikke ut til at du har noen applikasjoner som st\u00f8tter synkronisering.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Velkommen til Media Browser Dashbord",
-    "HeaderWelcomeToMediaBrowserWebClient": "Velkommen til Media Browser Web Klient",
+    "HeaderWelcomeToMediaBrowserWebClient": "Velkommen til Media Browser Webklient",
     "ButtonTakeTheTour": "Bli med p\u00e5 omvisning",
-    "HeaderWelcomeBack": "Welcome back!",
-    "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
-    "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
+    "HeaderWelcomeBack": "Velkommen tilbake!",
+    "TitleSync": "Synk",
+    "TitlePlugins": "Plugins",
+    "ButtonTakeTheTourToSeeWhatsNew": "Ta en titt p\u00e5 hva som er nytt",
+    "MessageNoSyncJobsFound": "Ingen synkroniseringsjobber funnet. Opprett en synkroniseringsjobb ved hjelp av Synkroniseringsknappene i biblioteket",
     "HeaderLibraryAccess": "Bibliotek tilgang",
     "HeaderChannelAccess": "Kanal tilgang",
-    "HeaderDeviceAccess": "Device Access",
-    "HeaderSelectDevices": "Select Devices",
-    "ButtonCancelItem": "Cancel item",
-    "ButtonQueueForRetry": "Queue for retry",
-    "ButtonReenable": "Re-enable",
+    "HeaderDeviceAccess": "Enhetstilgang",
+    "HeaderSelectDevices": "Velg enheter",
+    "ButtonCancelItem": "Avbryt element",
+    "ButtonQueueForRetry": "K\u00f8 for \u00e5 pr\u00f8ve igjen",
+    "ButtonReenable": "Skru p\u00e5 igjen",
     "ButtonLearnMore": "L\u00e6re mer",
-    "SyncJobItemStatusSyncedMarkForRemoval": "Marked for removal",
+    "SyncJobItemStatusSyncedMarkForRemoval": "Markert for fjerning",
     "LabelAbortedByServerShutdown": "(Avbrutt av server shutdown)",
     "LabelScheduledTaskLastRan": "Sist kj\u00f8rt {0}, tar {1}.",
     "HeaderDeleteTaskTrigger": "Slett Oppgave Trigger",
@@ -95,18 +115,21 @@
     "LabelVersionInstalled": "{0} installert.",
     "LabelNumberReviews": "{0} Anmeldelser",
     "LabelFree": "Gratis",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Velg Lyd",
     "HeaderSelectSubtitles": "Velg Undertekst",
-    "ButtonMarkForRemoval": "Remove from device",
-    "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
+    "ButtonMarkForRemoval": "Fjern fra enheten.",
+    "ButtonUnmarkForRemoval": "Avbryt fjerning fra enheten",
     "LabelDefaultStream": "(Standard)",
     "LabelForcedStream": "(Tvunget)",
     "LabelDefaultForcedStream": "(Standard\/Tvunget)",
     "LabelUnknownLanguage": "Ukjent spr\u00e5k",
-    "MessageConfirmSyncJobItemCancellation": "Are you sure you wish to cancel this item?",
+    "MessageConfirmSyncJobItemCancellation": "Er du sikker p\u00e5 at du vil kansellere dette elementet?",
     "ButtonMute": "Mute",
-    "ButtonUnmute": "unmute",
+    "ButtonUnmute": "Lyd p\u00e5",
     "ButtonStop": "Stopp",
     "ButtonNextTrack": "Neste Spor",
     "ButtonPause": "Pause",
@@ -123,10 +146,10 @@
     "ButtonViewNotifications": "Se meldinger.",
     "ButtonMarkTheseRead": "Maker disse som lest",
     "ButtonClose": "Lukk",
-    "LabelAllPlaysSentToPlayer": "All avspill vil bli sendt til den valgte spilleren.",
+    "LabelAllPlaysSentToPlayer": "Alt som spilles vil bli sendt til den valgte spilleren.",
     "MessageInvalidUser": "Ugyldig brukernavn eller passord. Vennligst pr\u00f8v igjen.",
     "HeaderLoginFailure": "P\u00e5loggingsfeil",
-    "HeaderAllRecordings": "Alle Opptak",
+    "HeaderAllRecordings": "Alle opptak",
     "RecommendationBecauseYouLike": "Fordi du liker {0}",
     "RecommendationBecauseYouWatched": "Fordi du s\u00e5 {0}",
     "RecommendationDirectedBy": "Regissert av {0}",
@@ -164,8 +187,8 @@
     "StatusRecordingProgram": "Opptak {0}",
     "StatusWatchingProgram": "Ser P\u00e5 {0}",
     "HeaderSplitMedia": "Del Media Fra Hverandre",
-    "MessageConfirmSplitMedia": "Er du sikker at du vil splitte media kilden i separerte elementer?",
-    "HeaderError": "Error",
+    "MessageConfirmSplitMedia": "Er du sikker at du vil splitte mediakilden i separerte elementer?",
+    "HeaderError": "Feil",
     "MessagePleaseSelectOneItem": "Vennligst velg minst ett element.",
     "MessagePleaseSelectTwoItems": "Vennligst velg minst to elementer.",
     "MessageTheFollowingItemsWillBeGrouped": "F\u00f8lgende titler vil bli gruppert til ett element:",
@@ -176,17 +199,17 @@
     "HeaderLatestMedia": "Siste Media",
     "ButtonMoreItems": "Mer...",
     "ButtonMore": "Mer",
-    "HeaderFavoriteMovies": "Favoritt Filmer",
-    "HeaderFavoriteShows": "Favoritt Serier",
-    "HeaderFavoriteEpisodes": "Favoritt Episoder",
-    "HeaderFavoriteGames": "Favoritt Spill",
+    "HeaderFavoriteMovies": "Favorittfilmer",
+    "HeaderFavoriteShows": "Favorittserier",
+    "HeaderFavoriteEpisodes": "Favorittepisoder",
+    "HeaderFavoriteGames": "Favorittspill",
     "HeaderRatingsDownloads": "Rangering \/ Nedlasting",
     "HeaderConfirmProfileDeletion": "Bekreft sletting av profil",
     "MessageConfirmProfileDeletion": "Er du sikker p\u00e5 at du vil slette denne profilen?",
-    "HeaderSelectServerCachePath": "Velg Server Cache Sti",
-    "HeaderSelectTranscodingPath": "Velg Transcoding Midlertidig Sti",
-    "HeaderSelectImagesByNamePath": "Velg Bilder etter Navn Sti",
-    "HeaderSelectMetadataPath": "Velg Metadata Sti",
+    "HeaderSelectServerCachePath": "Velg Sti for Server Cache",
+    "HeaderSelectTranscodingPath": "Velg Sti for Midlertidig Transcoding",
+    "HeaderSelectImagesByNamePath": "Velg Sti for Bilder etter Navn",
+    "HeaderSelectMetadataPath": "Velg Sti for Metadata",
     "HeaderSelectServerCachePathHelp": "Bla eller skriv stien som skal brukes for server cache filer. Mappen m\u00e5 v\u00e6re skrivbar.",
     "HeaderSelectTranscodingPathHelp": "Bla eller skriv stien som skal brukes for transcoding av midlertidige filer. Mappen m\u00e5 v\u00e6re skrivbar.",
     "HeaderSelectImagesByNamePathHelp": "Bla eller skriv stien til dine elementer etter navn mappe. Mappen m\u00e5 v\u00e6re skrivbar.",
@@ -194,7 +217,7 @@
     "HeaderSelectChannelDownloadPath": "Velg Nedlastingsti For Kanal",
     "HeaderSelectChannelDownloadPathHelp": "Bla igjennom eller skriv en sti som brukes for lagring av cache filer. Mappen m\u00e5 v\u00e6re skrivbar.",
     "OptionNewCollection": "Ny...",
-    "ButtonAdd": "Legg Til",
+    "ButtonAdd": "Legg til",
     "ButtonRemove": "Fjern",
     "LabelChapterDownloaders": "Kapittel nedlastinger:",
     "LabelChapterDownloadersHelp": "Aktiver og ranger din foretrukne kapittel nedlasting i f\u00f8lgende prioritet. Lavere prioritet nedlastinger vil kun bli brukt for \u00e5 fylle inn manglende informasjon",
@@ -212,7 +235,7 @@
     "MessageDuplicatesWillBeDeleted": "I tillegg vil f\u00f8lgende duplisering bli slettet:",
     "MessageFollowingFileWillBeMovedFrom": "F\u00f8lgende fil har blitt flyttet fra:",
     "MessageDestinationTo": "til:",
-    "HeaderSelectWatchFolder": "Velg Se Mappe",
+    "HeaderSelectWatchFolder": "Velg overv\u00e5ket mappe",
     "HeaderSelectWatchFolderHelp": "S\u00f8k igjennom eller velg sti for din Se mappe. Mappen m\u00e5 v\u00e6re skrivbar.",
     "OrganizePatternResult": "Resultat: {0}",
     "HeaderRestart": "Omstart",
@@ -220,8 +243,8 @@
     "MessageConfirmRestart": "Er du sikker p\u00e5 at du vil gi Media Browser Server en omstart?",
     "MessageConfirmShutdown": "Er du sikker p\u00e5 du vil sl\u00e5 av Media Browser Server?",
     "ButtonUpdateNow": "Oppdater N\u00e5",
-    "ValueItemCount": "{0} item",
-    "ValueItemCountPlural": "{0} items",
+    "ValueItemCount": "{0} element",
+    "ValueItemCountPlural": "{0} elementer",
     "NewVersionOfSomethingAvailable": "En ny versjon av {0} er tilgjengelig!",
     "VersionXIsAvailableForDownload": "Vesjon {0} er n\u00e5 tilgjengelig for nedlasting.",
     "LabelVersionNumber": "Versjon {0}",
@@ -230,10 +253,10 @@
     "LabelPlayMethodDirectPlay": "Direkte Avspilling",
     "LabelAudioCodec": "Lyd: {0}",
     "LabelVideoCodec": "Video: {0}",
-    "LabelLocalAccessUrl": "Local access: {0}",
+    "LabelLocalAccessUrl": "Lokal tilgang: {0}",
     "LabelRemoteAccessUrl": "Ekstern tilgang: {0}",
-    "LabelRunningOnPort": "Running on http port {0}.",
-    "LabelRunningOnPorts": "Running on http port {0}, and https port {1}.",
+    "LabelRunningOnPort": "Kj\u00f8rer p\u00e5 http port {0}.",
+    "LabelRunningOnPorts": "Kj\u00f8rer p\u00e5 http port {0} og https port {1}.",
     "HeaderLatestFromChannel": "Siste fra {0}",
     "LabelUnknownLanaguage": "Ukjent Spr\u00e5k",
     "HeaderCurrentSubtitles": "N\u00e5v\u00e6rende undertekster",
@@ -242,11 +265,11 @@
     "ButtonRemoteControl": "Ekstern Kontroll",
     "HeaderLatestTvRecordings": "Siste Opptak",
     "ButtonOk": "Ok",
-    "ButtonCancel": "avbryt",
+    "ButtonCancel": "Avbryt",
     "ButtonRefresh": "Oppdater",
     "LabelCurrentPath": "N\u00e5v\u00e6rende sti:",
     "HeaderSelectMediaPath": "Velg Media Sti",
-    "HeaderSelectPath": "Select Path",
+    "HeaderSelectPath": "Velg sti",
     "ButtonNetwork": "Nettverk",
     "MessageDirectoryPickerInstruction": "Nettverksti kan skrives inn manuelt i tilfelle Nettverk-knappen ikke klarer \u00e5 lokalisere enhetene dine. For eksempel {0} eller {1}.",
     "HeaderMenu": "Meny",
@@ -257,11 +280,11 @@
     "ButtonResume": "Fortsette",
     "HeaderScenes": "Scener",
     "HeaderAudioTracks": "Lydspor",
-    "HeaderLibraries": "Libraries",
+    "HeaderLibraries": "Bibliotek",
     "HeaderSubtitles": "Undertekster",
-    "HeaderVideoQuality": "Video Kvalitet",
-    "MessageErrorPlayingVideo": "Det oppstod en error ved avspilling av vidoen.",
-    "MessageEnsureOpenTuner": "Vennligst s\u00f8rg for at det minst er en \u00e5pen tuner tilgjengelig.",
+    "HeaderVideoQuality": "Videookvalitet",
+    "MessageErrorPlayingVideo": "Det oppstod en feil ved avspilling av vidoen.",
+    "MessageEnsureOpenTuner": "Vennligst s\u00f8rg for at det minst er \u00e9n \u00e5pen tuner tilgjengelig.",
     "ButtonHome": "Hjem",
     "ButtonDashboard": "Dashbord",
     "ButtonReports": "Rapporter",
@@ -271,11 +294,11 @@
     "HeaderAlbum": "Album",
     "HeaderAlbumArtist": "Album Artist",
     "HeaderArtist": "Artist",
-    "LabelAddedOnDate": "Lag Til {0}",
+    "LabelAddedOnDate": "Lagt til {0}",
     "ButtonStart": "Start",
     "HeaderChannels": "Kanaler",
-    "HeaderMediaFolders": "Media Mapper",
-    "HeaderBlockItemsWithNoRating": "Block content with no rating information:",
+    "HeaderMediaFolders": "Mediemapper",
+    "HeaderBlockItemsWithNoRating": "Blokker innhold uten rating:",
     "OptionBlockOthers": "Andre",
     "OptionBlockTvShows": "TV Serier",
     "OptionBlockTrailers": "Trailere",
@@ -285,10 +308,10 @@
     "OptionBlockGames": "Spill",
     "OptionBlockLiveTvPrograms": "Live TV Programmer",
     "OptionBlockLiveTvChannels": "Live TV Kanaler",
-    "OptionBlockChannelContent": "Internet Kanal Innhold",
+    "OptionBlockChannelContent": "Innhold fra Internettkanal",
     "ButtonRevoke": "Tilbakekall",
-    "MessageConfirmRevokeApiKey": "Er du sikker p\u00e5 at du vil ta tilbakekalle denne api n\u00f8kkelen? Applikasjonens forbindelse til Media Browser vil bli br\u00e5tt avsluttet.",
-    "HeaderConfirmRevokeApiKey": "Tilbakekall Api N\u00f8kkel",
+    "MessageConfirmRevokeApiKey": "Er du sikker p\u00e5 at du vil tilbakekalle denne API-n\u00f8kkelen? Applikasjonens forbindelse til Media Browser vil bli avsluttet umiddelbart.",
+    "HeaderConfirmRevokeApiKey": "Tilbakekall API-n\u00f8kkel",
     "ValueContainer": "Kontainer: {0}",
     "ValueAudioCodec": "Lyd Kodek: {0}",
     "ValueVideoCodec": "Video Kodek: {0}",
@@ -297,24 +320,24 @@
     "LabelAll": "Alle",
     "HeaderDeleteImage": "Slett bilde",
     "MessageFileNotFound": "Fant ikke fil.",
-    "MessageFileReadError": "En error oppstod n\u00e5r filen skulle leses",
+    "MessageFileReadError": "En feil oppstod n\u00e5r filen skulle leses.",
     "ButtonNextPage": "Neste Side",
     "ButtonPreviousPage": "Forrige Side",
     "ButtonMoveLeft": "Flytt til venstre",
     "ButtonMoveRight": "Flytt til h\u00f8yre",
     "ButtonBrowseOnlineImages": "Bla igjennom bilder online",
     "HeaderDeleteItem": "Slett element",
-    "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?",
+    "ConfirmDeleteItem": "Sletter elementet fra b\u00e5de filsystemet og biblioteket. Er du sikker p\u00e5 at du vil fortsette?",
     "MessagePleaseEnterNameOrId": "Vennligst skriv ett navn eller en ekstern id.",
     "MessageValueNotCorrect": "Verdien som ble skrevet er ikke korrekt. Vennligst pr\u00f8v igjen.",
     "MessageItemSaved": "Element lagret.",
-    "MessagePleaseAcceptTermsOfServiceBeforeContinuing": "Please accept the terms of service before continuing.",
+    "MessagePleaseAcceptTermsOfServiceBeforeContinuing": "Vennligst aksepter tjenestevilk\u00e5rene f\u00f8r du fortsetter.",
     "OptionEnded": "Avsluttet",
     "OptionContinuing": "Fortsetter",
     "OptionOff": "Av",
     "OptionOn": "P\u00e5",
     "ButtonSettings": "Innstillinger",
-    "ButtonUninstall": "Uninstall",
+    "ButtonUninstall": "Avinstaller",
     "HeaderFields": "Felt",
     "HeaderFieldsHelp": "Skyv ett felt til \"av\" for \u00e5 l\u00e5se det og for \u00e5 unng\u00e5 at data blir forandret.",
     "HeaderLiveTV": "Live TV",
@@ -336,14 +359,14 @@
     "OptionPeople": "Person",
     "OptionRuntime": "Spilletid",
     "OptionProductionLocations": "Produksjonsplass",
-    "OptionBirthLocation": "F\u00f8dselsplass",
+    "OptionBirthLocation": "F\u00f8dested",
     "LabelAllChannels": "Alle kanaler",
     "LabelLiveProgram": "LIVE",
     "LabelNewProgram": "NY",
     "LabelPremiereProgram": "PREMIERE",
     "LabelHDProgram": "HD",
-    "HeaderChangeFolderType": "Change Content Type",
-    "HeaderChangeFolderTypeHelp": "To change the type, please remove and rebuild the folder with the new type.",
+    "HeaderChangeFolderType": "Endre innholdstype",
+    "HeaderChangeFolderTypeHelp": "For \u00e5 endre type, fjern og opprett ny mappe med den nye typen.",
     "HeaderAlert": "Varsling",
     "MessagePleaseRestart": "Vennligst utf\u00f8r en omstart for \u00e5 fullf\u00f8re oppdatering.",
     "ButtonRestart": "Restart",
@@ -353,7 +376,7 @@
     "ButtonSignOut": "Logg Ut",
     "ButtonMyProfile": "Min Profil",
     "ButtonMyPreferences": "Mine Preferanser",
-    "MessageBrowserDoesNotSupportWebSockets": "Denne nettleseren st\u00f8tter ikke web sockets. For en bedre brukeropplevelse pr\u00f8v en nyere nettleser som eksemepel Chrome, Firefox, IE10+, Safari (IOS) eller Opera.",
+    "MessageBrowserDoesNotSupportWebSockets": "Denne nettleseren st\u00f8tter ikke web sockets. For en bedre brukeropplevelse pr\u00f8v en nyere nettleser som for eksemepel Chrome, Firefox, IE10+, Safari (IOS) eller Opera.",
     "LabelInstallingPackage": "Installerer {0}",
     "LabelPackageInstallCompleted": "{0} installering fullf\u00f8rt.",
     "LabelPackageInstallFailed": "{0} installasjon feilet.",
@@ -370,7 +393,7 @@
     "TabHelp": "Hjelp",
     "TabScheduledTasks": "Planlagte Oppgaver",
     "ButtonFullscreen": "Fullskjerm",
-    "ButtonAudioTracks": "Lyd spor",
+    "ButtonAudioTracks": "Lydspor",
     "ButtonSubtitles": "Undertekster",
     "ButtonScenes": "Scener",
     "ButtonQuality": "Kvalitet",
@@ -378,7 +401,7 @@
     "HeaderSelectPlayer": "Velg Spiller",
     "ButtonSelect": "Velg",
     "ButtonNew": "Ny",
-    "MessageInternetExplorerWebm": "For det beste resultatet med Internet Explorer anbefales det at du installerer WebM avspillings programtillegg.",
+    "MessageInternetExplorerWebm": "For det beste resultatet med Internet Explorer anbefales det at du installerer WebM programtillegg for videoavspilling.",
     "HeaderVideoError": "Video Error",
     "ButtonAddToPlaylist": "Legg til spilleliste",
     "HeaderAddToPlaylist": "Legg til Spilleliste",
@@ -391,14 +414,14 @@
     "ButtonViewSeriesRecording": "Se serie opptak",
     "ValueOriginalAirDate": "Original lanseringsdato: {0}",
     "ButtonRemoveFromPlaylist": "Fjern fra spilleliste",
-    "HeaderSpecials": "Spescials",
+    "HeaderSpecials": "Specials",
     "HeaderTrailers": "Trailere",
     "HeaderAudio": "Lyd",
     "HeaderResolution": "Oppl\u00f8sning",
     "HeaderVideo": "Video",
     "HeaderRuntime": "Spilletid",
     "HeaderCommunityRating": "Fellesskap anmeldelse",
-    "HeaderParentalRating": "Foreldresensur:",
+    "HeaderParentalRating": "Foreldresensur",
     "HeaderReleaseDate": "Utgivelsesdato",
     "HeaderDateAdded": "Dato lagt til",
     "HeaderSeries": "Serier",
@@ -442,41 +465,41 @@
     "PersonTypePerson": "Person",
     "LabelTitleDisplayOrder": "Tittel visnings rekkef\u00f8lge:",
     "OptionSortName": "Sorterings navn",
-    "OptionReleaseDate": "Lanserings dato",
+    "OptionReleaseDate": "Lanseringsdato",
     "LabelSeasonNumber": "Sesong nummer:",
     "LabelDiscNumber": "Disk nummer",
-    "LabelParentNumber": "Parent number",
+    "LabelParentNumber": "Forelder-ID",
     "LabelEpisodeNumber": "Episode nummer:",
-    "LabelTrackNumber": "Spor nummer",
+    "LabelTrackNumber": "Spor nummer:",
     "LabelNumber": "Nummer:",
     "LabelReleaseDate": "Utgivelsesdato:",
     "LabelEndDate": "Slutt dato:",
     "LabelYear": "\u00c5r:",
     "LabelDateOfBirth": "F\u00f8dseldato:",
     "LabelBirthYear": "F\u00f8dsels\u00e5r:",
-    "LabelBirthDate": "Birth date:",
-    "LabelDeathDate": "D\u00f8ds dato:",
-    "HeaderRemoveMediaLocation": "Fjern Media Mappe",
+    "LabelBirthDate": "F\u00f8dselsdato:",
+    "LabelDeathDate": "D\u00f8dsdato:",
+    "HeaderRemoveMediaLocation": "Fjern Mediamappe",
     "MessageConfirmRemoveMediaLocation": "Er du sikker p\u00e5 at du vil slette dette stedet??",
-    "HeaderRenameMediaFolder": "Fjern Media Mappe",
+    "HeaderRenameMediaFolder": "Endre navn p\u00e5 Mediamappe",
     "LabelNewName": "Nytt navn:",
-    "HeaderAddMediaFolder": "Legg til media-mappe",
+    "HeaderAddMediaFolder": "Legg til mediamappe",
     "HeaderAddMediaFolderHelp": "Navn (Filmer, Musikk, TV, etc):",
-    "HeaderRemoveMediaFolder": "Fjern Media Mappe",
-    "MessageTheFollowingLocationWillBeRemovedFromLibrary": "F\u00f8lgende media steder vil bli fjernet fra ditt bibliotek:",
-    "MessageAreYouSureYouWishToRemoveMediaFolder": "Er du sikker p\u00e5 at dul vil slette denne media mappen?",
+    "HeaderRemoveMediaFolder": "Fjern Mediamappe",
+    "MessageTheFollowingLocationWillBeRemovedFromLibrary": "F\u00f8lgende mapper med media vil bli fjernet fra ditt bibliotek:",
+    "MessageAreYouSureYouWishToRemoveMediaFolder": "Er du sikker p\u00e5 at dul vil slette denne media-mappen?",
     "ButtonRename": "Gi nytt navn",
     "ButtonChangeType": "Endre type",
     "HeaderMediaLocations": "Media Steder",
-    "LabelContentTypeValue": "Content type: {0}",
+    "LabelContentTypeValue": "Innholdstype {0}",
     "LabelPathSubstitutionHelp": "Valgfritt: Sti erstatter kan koble server stier til nettverkressurser som klienter har tilgang til for direkte avspilling.",
-    "FolderTypeUnset": "Unset (mixed content)",
+    "FolderTypeUnset": "Ikke bestemt (variert innhold)",
     "FolderTypeMovies": "Filmer",
     "FolderTypeMusic": "Musikk",
-    "FolderTypeAdultVideos": "Voksen videoer",
+    "FolderTypeAdultVideos": "Voksen-videoer",
     "FolderTypePhotos": "Foto",
-    "FolderTypeMusicVideos": "Musikk videoer",
-    "FolderTypeHomeVideos": "Hjemme videoer",
+    "FolderTypeMusicVideos": "Musikk-videoer",
+    "FolderTypeHomeVideos": "Hjemme-videoer",
     "FolderTypeGames": "Spill",
     "FolderTypeBooks": "B\u00f8ker",
     "FolderTypeTvShows": "TV",
@@ -538,7 +561,7 @@
     "ValueOneGame": "1 spill",
     "ValueGameCount": "{0} spill",
     "ValueOneAlbum": "1 album",
-    "ValueAlbumCount": "{0} albumer",
+    "ValueAlbumCount": "{0} album",
     "ValueOneSong": "1 sang",
     "ValueSongCount": "{0} sanger",
     "ValueOneMusicVideo": "1 musikkvideo",
@@ -546,12 +569,12 @@
     "HeaderOffline": "Offline",
     "HeaderUnaired": "Ikke sendt",
     "HeaderMissing": "Mangler",
-    "ButtonWebsite": "Nettsted:",
+    "ButtonWebsite": "Nettsted",
     "TooltipFavorite": "Favoritt",
     "TooltipLike": "Liker",
     "TooltipDislike": "Misliker",
     "TooltipPlayed": "Sett",
-    "ValueSeriesYearToPresent": "{0}-Tilgjengelig",
+    "ValueSeriesYearToPresent": "{0}-N\u00e5",
     "ValueAwards": "Priser: {0}",
     "ValueBudget": "Budsjett: {0}",
     "ValueRevenue": "Inntjening: {0}",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premiere {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studioer: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Spesiell - {0}",
     "LabelLimit": "Grense:",
     "ValueLinks": "Lenker: {0}",
@@ -592,7 +616,7 @@
     "HeaderOtherItems": "Andre elementer",
     "ButtonFullReview": "Full anmeldelse",
     "ValueAsRole": "som {0}",
-    "ValueGuestStar": "Gjeste artist",
+    "ValueGuestStar": "Gjesteartist",
     "MediaInfoSize": "St\u00f8rrelse",
     "MediaInfoPath": "Sti",
     "MediaInfoFormat": "Format",
@@ -624,14 +648,14 @@
     "MediaInfoRefFrames": "Ref frames",
     "TabPlayback": "Spill av",
     "TabNotifications": "Varslinger",
-    "TabExpert": "Expert",
+    "TabExpert": "Ekspert",
     "HeaderSelectCustomIntrosPath": "Velg tilpasset intro sti",
     "HeaderRateAndReview": "Ranger og anmeld",
     "HeaderThankYou": "Takk",
     "MessageThankYouForYourReview": "Takk for din anmeldelse.",
     "LabelYourRating": "Din vurdering:",
     "LabelFullReview": "Full anmeldelse:",
-    "LabelShortRatingDescription": "Kort vurderings sammendrag:",
+    "LabelShortRatingDescription": "Kort sammendrag av vurdering:",
     "OptionIRecommendThisItem": "Jeg anbefaler dette elementet",
     "WebClientTourContent": "Vis dine nylig tilf\u00f8yde medier, neste episodene og mer. De gr\u00f8nne sirklene viser hvor mange uspilte elementer du har.",
     "WebClientTourMovies": "Spill av filmer, trailere og mer fra hvilken som helst enhet med en nettleser",
@@ -642,14 +666,14 @@
     "WebClientTourCollections": "Lag dine egne samlebokser",
     "WebClientTourUserPreferences1": "Brukerpreferanser lar deg tilpasse m\u00e5ten biblioteket er presentert i alle Media Browser apper",
     "WebClientTourUserPreferences2": "Konfigurer spr\u00e5kpreferanse for lyd og undertekst en gang, for hver media nettleser app",
-    "WebClientTourUserPreferences3": "Utform webklient startsiden slik du \u00f8nsker",
-    "WebClientTourUserPreferences4": "Konfigurer bakgrunner, tema sanger og eksterne avspillere",
+    "WebClientTourUserPreferences3": "Utform startsiden slik du \u00f8nsker den.",
+    "WebClientTourUserPreferences4": "Konfigurer bakgrunner, temasanger og eksterne avspillere",
     "WebClientTourMobile1": "Webklienten fungerer bra p\u00e5 smarttelefoner og nettbrett ...",
     "WebClientTourMobile2": "og enkelt styrer andre enheter og mediabrowser apps",
-    "WebClientTourMySync": "Sync your personal media to your devices for offline viewing.",
+    "WebClientTourMySync": "Synkronis\u00e9r dine personlige mediefiler til dine enheter for offline bruk.",
     "MessageEnjoyYourStay": "Nyt oppholdet",
-    "DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
-    "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
+    "DashboardTourDashboard": "Server dashboard lar deg overv\u00e5ke serveren og brukerene. Du kan til enhver tid se hvem som gj\u00f8r hva, og hvor de er.",
+    "DashboardTourHelp": "Applikasjonens hjelpesystem har knapper som gir enkel tilgang til relevant dokumentasjon fra wikien.",
     "DashboardTourUsers": "Opprett bruker kontoer enkelt for dine venner og familie, hver med deres egne rettigheter, bibliotek tillgang, foreldre kontroll og mere til.",
     "DashboardTourCinemaMode": "Kino-modus bringer kinoopplevelsen direkte til din stue med muligheten til \u00e5 spille trailere og tilpassede introer f\u00f8r filmen begynner.",
     "DashboardTourChapters": "Aktiver generering av kapittel bilder  for dine videoer for en mer behagelig presentasjon mens du ser p\u00e5.",
@@ -658,10 +682,10 @@
     "DashboardTourNotifications": "Send meldinger automatisk for server handlinger til dine mobile enheter, epost, etc.",
     "DashboardTourScheduledTasks": "Administrer enkelt operasjoner som kan ta lang tid med oppgaveplanlegging. Bestem n\u00e5r de kj\u00f8rer og hvor ofte.",
     "DashboardTourMobile": "Media Browser dashboard fungerer fint p\u00e5 en smart telefon og nettbrett. Administrer din server fra din h\u00e5ndflate n\u00e5r som helst, hvor som helst.",
-    "DashboardTourSync": "Sync your personal media to your devices for offline viewing.",
+    "DashboardTourSync": "Synkroniser personlige mediafiler til din enhet for \u00e5 se p\u00e5 offline.",
     "MessageRefreshQueued": "Oppfrisk k\u00f8en",
     "TabDevices": "Enheter",
-    "TabExtras": "Extras",
+    "TabExtras": "Ekstra",
     "DeviceLastUsedByUserName": "Sist brukt av {0}",
     "HeaderDeleteDevice": "Slett Enhet",
     "DeleteDeviceConfirmation": "Er du sikker p\u00e5 at du vil slette denne enheten? Den vil gjenoppst\u00e5 neste gang en bruker logger inn med den.",
@@ -674,8 +698,8 @@
     "HeaderInvitationSent": "Invitasjon Sendt",
     "MessageInvitationSentToUser": "En epost har blitt sent til {0} med oppfordring til \u00e5 godta invitasjonen din.",
     "MessageInvitationSentToNewUser": "En epost har blitt sendt til {0} med en invitasjon til \u00e5 registrere seg med Media Browser.",
-    "HeaderConnectionFailure": "Tilkobling feiler",
-    "MessageUnableToConnectToServer": "We're unable to connect to the selected server right now. Please ensure it is running and try again.",
+    "HeaderConnectionFailure": "Tilkobling feilet",
+    "MessageUnableToConnectToServer": "Vi kan ikke kontakte angitt server akkurat n\u00e5. Sjekk at den er startet og pr\u00f8v igjen.",
     "ButtonSelectServer": "Velg server",
     "MessagePluginConfigurationRequiresLocalAccess": "Logg inn p\u00e5 din lokale server direkte for \u00e5 konfigurere dette programtillegget.",
     "MessageLoggedOutParentalControl": "Tilgangen er forel\u00f8pig begrenset. Vennligst pr\u00f8v igjen senere.",
@@ -683,44 +707,42 @@
     "ButtonAccept": "Godta",
     "ButtonReject": "Avvis",
     "HeaderForgotPassword": "Glemt passord",
-    "MessageContactAdminToResetPassword": "Please contact your system administrator to reset your password.",
-    "MessageForgotPasswordInNetworkRequired": "Please try again within your home network to initiate the password reset process.",
-    "MessageForgotPasswordFileCreated": "The following file has been created on your server and contains instructions on how to proceed:",
-    "MessageForgotPasswordFileExpiration": "The reset pin will expire at {0}.",
-    "MessageInvalidForgotPasswordPin": "An invalid or expired pin was entered. Please try again.",
-    "MessagePasswordResetForUsers": "Passwords have been removed for the following users:",
-    "HeaderInviteGuest": "Invite Guest",
-    "ButtonLinkMyMediaBrowserAccount": "Link my account now",
-    "MessageConnectAccountRequiredToInviteGuest": "In order to invite guests you need to first link your Media Browser account to this server.",
+    "MessageContactAdminToResetPassword": "Vennligst kontakte administrator for hjelp til \u00e5 resette passordet ditt.",
+    "MessageForgotPasswordInNetworkRequired": "Vennligst pr\u00f8v igjen fra hjemmenettet ditt for \u00e5 starte prosessen med \u00e5 gjenopprette passordet ditt.",
+    "MessageForgotPasswordFileCreated": "F\u00f8lgende fil er opprettet p\u00e5 serveren og inneholder instruksjoner om hvordan du kan fortsette:",
+    "MessageForgotPasswordFileExpiration": "PIN-koden for gjenoppretting er gyldig til {0}.",
+    "MessageInvalidForgotPasswordPin": "Ugyldig eller utg\u00e5tt PIN kode angitt. Vennligst pr\u00f8v igjen.",
+    "MessagePasswordResetForUsers": "Passordet er fjernet for f\u00f8lgende brukere:",
+    "HeaderInviteGuest": "Inviter gjest",
+    "ButtonLinkMyMediaBrowserAccount": "Link kontoen min n\u00e5",
+    "MessageConnectAccountRequiredToInviteGuest": "For \u00e5 kunne invitere gjester m\u00e5 du f\u00f8rst linke kontoen din p\u00e5 Media Browser til denne serveren.",
     "ButtonSync": "Synk",
-    "SyncMedia": "Sync Media",
-    "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "SyncMedia": "Synkroniser media",
+    "HeaderCancelSyncJob": "Avbryt synkronisering",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Synk",
-    "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
-    "MessageSyncJobCreated": "Sync job created.",
-    "LabelSyncTo": "Sync to:",
-    "LabelSyncJobName": "Sync job name:",
-    "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
-    "HeaderSettings": "Settings",
-    "OptionAutomaticallySyncNewContent": "Automatically sync new content",
-    "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
-    "OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only",
-    "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.",
-    "LabelItemLimit": "Item limit:",
-    "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.",
-    "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin",
-    "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin",
-    "MessageUnsetContentHelp": "Content will be displayed as plain folders. For best results use the metadata manager to set the content types of sub-folders.",
-    "SyncJobItemStatusQueued": "Queued",
-    "SyncJobItemStatusConverting": "Converting",
-    "SyncJobItemStatusTransferring": "Transferring",
-    "SyncJobItemStatusSynced": "Synced",
-    "SyncJobItemStatusFailed": "Failed",
-    "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "MessagePleaseSelectDeviceToSyncTo": "Velg enhet \u00e5 synkronisere til.",
+    "MessageSyncJobCreated": "Synkroniseringsjobb p\u00e5begynt.",
+    "LabelSyncTo": "Synkroniser til:",
+    "LabelSyncJobName": "Navn p\u00e5 synkroniseringsjobb:",
+    "LabelQuality": "Kvalitet:",
+    "HeaderSettings": "Innstillinger",
+    "OptionAutomaticallySyncNewContent": "Automatisk synkroniser nytt innhold",
+    "OptionAutomaticallySyncNewContentHelp": "Nytt innhold lagt til i denne kategorien vil bli automatisk synkronisert til enheten.",
+    "OptionSyncUnwatchedVideosOnly": "Synkroniser kun usette videoer",
+    "OptionSyncUnwatchedVideosOnlyHelp": "Kun usette videoer blir synkronisert, og videoer blir fjernet fra enheten s\u00e5 snart de er sett.",
+    "LabelItemLimit": "Begrenset antall:",
+    "LabelItemLimitHelp": "Valgfri. Sett en grense for hvor mange enheter som skal synkroniseres.",
+    "MessageBookPluginRequired": "Forutsetter at programtillegget bokhylle er installert",
+    "MessageGamePluginRequired": "Forutsetter at programtillegget GameBrowser er installert",
+    "MessageUnsetContentHelp": "Innhold vises som enkle mapper. For beste resultat, bruk metadata for \u00e5 sette innholdstype for mapper.",
+    "SyncJobItemStatusQueued": "I k\u00f8",
+    "SyncJobItemStatusConverting": "Konverterer",
+    "SyncJobItemStatusTransferring": "Overf\u00f8rer",
+    "SyncJobItemStatusSynced": "Synkronisert",
+    "SyncJobItemStatusFailed": "Feilet",
+    "SyncJobItemStatusRemovedFromDevice": "Fjernet fra enheten",
+    "SyncJobItemStatusCancelled": "Kansellert",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
index 295bca63a5..f40cd11ed0 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Dank u. Uw supporter sleutel is bijgewerkt.",
     "MessageKeyRemoved": "Dank u. Uw supporter sleutel is verwijderd.",
     "ErrorLaunchingChromecast": "Er is een fout opgetreden bij het starten van chromecast. Zorg ervoor dat uw apparaat is aangesloten op uw draadloze netwerk.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Tijdslimiet: 1 uur",
+    "ValueTimeLimitMultiHour": "Tijdslimiet: {0} uren",
+    "HeaderUsers": "Gebruikers",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Zoeken",
     "ValueDateCreated": "Datum aangemaakt: {0}",
     "LabelArtist": "Artiest",
@@ -49,14 +67,14 @@
     "ButtonHelp": "Hulp",
     "ButtonSave": "Opslaan",
     "ButtonDownload": "Download",
-    "SyncJobStatusQueued": "Queued",
+    "SyncJobStatusQueued": "In wachtrij",
     "SyncJobStatusConverting": "Converteren",
     "SyncJobStatusFailed": "Mislukt",
     "SyncJobStatusCancelled": "Afgebroken",
     "SyncJobStatusCompleted": "Gesynced",
     "SyncJobStatusReadyToTransfer": "Klaar om te Verzenden",
     "SyncJobStatusTransferring": "Verzenden",
-    "SyncJobStatusCompletedWithError": "Synced with errors",
+    "SyncJobStatusCompletedWithError": "Gesynchroniseerd met fouten",
     "SyncJobItemStatusReadyToTransfer": "Klaar om te Verzenden",
     "LabelCollection": "Collectie",
     "HeaderAddToCollection": "Toevoegen aan Collectie",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Voeg toe aan collectie",
     "HeaderSelectCertificatePath": "Selecteer Certificaat Pad",
     "ConfirmMessageScheduledTaskButton": "Deze operatie loopt normaal gesproken automatisch als een geplande taak. Het kan hier ook handmatig worden uitgevoerd. Om de geplande taak te configureren, zie:",
-    "HeaderSupporterBenefit": "Een supporter lidmaatschap biedt voordelen zoals toegang tot premium plug-ins, internet kanalen en meer. {0}Meer weten{1}.",
-    "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
+    "HeaderSupporterBenefit": "Een supporter lidmaatschap biedt voordelen zoals toegang tot synchronisatie, premium plug-ins, internet kanalen en meer. {0}Meer weten{1}.",
+    "LabelSyncNoTargetsHelp": "Het lijkt erop dat je momenteel geen apps hebt die synchroniseren ondersteunen.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welkom bij het Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welkom op de Media Browser Web Client",
     "ButtonTakeTheTour": "Volg de tour",
     "HeaderWelcomeBack": "Welkom terug!",
+    "TitleSync": "Synchroniseer",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Volg de tour om te zien wat nieuw is",
     "MessageNoSyncJobsFound": "Geen sync opdrachten gevonden. Maak sync opdrachten via de Synchronisatie knoppen in de web interface.",
     "HeaderLibraryAccess": "Bibliotheek toegang",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} ge\u00efnstalleerd",
     "LabelNumberReviews": "{0} Recensies",
     "LabelFree": "Gratis",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Selecteer Audio",
     "HeaderSelectSubtitles": "Selecteer Ondertitels",
     "ButtonMarkForRemoval": "Van apparaat verwijderen",
     "ButtonUnmarkForRemoval": "Afbreken verwijderen van apparaat",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Standaard)",
     "LabelForcedStream": "(Geforceerd)",
     "LabelDefaultForcedStream": "(Standaard \/ Georceerd)",
@@ -545,7 +568,7 @@
     "ValueMusicVideoCount": "{0} muziek video's",
     "HeaderOffline": "Offline",
     "HeaderUnaired": "Niet uitgezonden",
-    "HeaderMissing": "Missend",
+    "HeaderMissing": "Ontbreekt",
     "ButtonWebsite": "Website",
     "TooltipFavorite": "Favoriet",
     "TooltipLike": "Leuk",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studio's: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Speciaal - {0}",
     "LabelLimit": "Limiet:",
     "ValueLinks": "Links: {0}",
@@ -646,7 +670,7 @@
     "WebClientTourUserPreferences4": "Configureer achtergronden, theme songs en externe spelers",
     "WebClientTourMobile1": "De web client werk perfect op smartphones en tablets...",
     "WebClientTourMobile2": "en kan elke andere Media Browser app bedienen",
-    "WebClientTourMySync": "Sync your personal media to your devices for offline viewing.",
+    "WebClientTourMySync": "Synchroniseer je persoonlijke media naar je apparaten om het offline te bekijken.",
     "MessageEnjoyYourStay": "Geniet van uw verblijf",
     "DashboardTourDashboard": "Het server-dashboard steld u in staat uw server en uw gebruikers te monitoren . U zult altijd weten wie wat doet en waar ze zijn.",
     "DashboardTourHelp": "De in-app hulp bevat handige knoppen om wiki pagina's te openen die gaan over de informatie op het scherm.",
@@ -658,7 +682,7 @@
     "DashboardTourNotifications": "Meldingen van de server gebeurtenissen automatisch verzenden naar uw mobiele apparaat, e-mail en meer.",
     "DashboardTourScheduledTasks": "Beheer eenvoudig langlopende transacties met geplande taken. Beslis zelf wanneer ze worden uitgevoerd en hoe vaak.",
     "DashboardTourMobile": "Het dashboard van Media Browser werkt geweldig op smartphones en tablets. Beheer je server vanuit de palm van je hand, overal en altijd.",
-    "DashboardTourSync": "Sync your personal media to your devices for offline viewing.",
+    "DashboardTourSync": "Synchroniseer je persoonlijke media naar je apparaten om het offline te bekijken.",
     "MessageRefreshQueued": "Vernieuwen wachtrij",
     "TabDevices": "Apparaten",
     "TabExtras": "Extra's",
@@ -695,17 +719,13 @@
     "ButtonSync": "Synchronisatie",
     "SyncMedia": "Synchroniseer media",
     "HeaderCancelSyncJob": "Annuleer synchronisatie",
-    "CancelSyncJobConfirmation": "Weet u zeker dat u deze synchronistatie taak wilt annuleren? ",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Synchronisatie",
     "MessagePleaseSelectDeviceToSyncTo": "Selecteer een apparaat om mee te synchroniseren.",
     "MessageSyncJobCreated": "Synchronisatie taak gemaakt.",
     "LabelSyncTo": "Synchroniseer naar:",
     "LabelSyncJobName": "Naam synchroniseer taak:",
     "LabelQuality": "Kwaliteit",
-    "OptionOriginal": "Original",
-    "OptionHigh": "Hoog",
-    "OptionMedium": "Gemiddeld",
-    "OptionLow": "Laag",
     "HeaderSettings": "Instellingen",
     "OptionAutomaticallySyncNewContent": "Nieuwe inhoud automatisch synchroniseren",
     "OptionAutomaticallySyncNewContentHelp": "Nieuwe inhoud toegevoegd aan deze categorie wordt automatisch gesynchroniseerd met het apparaat.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Gesynchroniseerd",
     "SyncJobItemStatusFailed": "Mislukt",
     "SyncJobItemStatusRemovedFromDevice": "Van apparaat verwijderd",
-    "SyncJobItemStatusCancelled": "Geannuleerd"
+    "SyncJobItemStatusCancelled": "Geannuleerd",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
index 1665a0fc0b..4ff24e13fd 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "U\u017cytkownicy",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
index 0b32a1efcc..119f41e108 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Obrigado. Sua chave de colaborador foi atualizada.",
     "MessageKeyRemoved": "Obrigado. Sua chave de colaborador foi removida.",
     "ErrorLaunchingChromecast": "Ocorreu um erro ao iniciar o chromecast. Por favor verifique se seu dispositivo est\u00e1 conectado \u00e0 sua rede sem fio.",
+    "MessageErrorLoadingSupporterInfo": "Ocorreu um erro ao carregar a informa\u00e7\u00e3o do colaborador. Por favor, tente novamente mais tarde.",
+    "MessageLinkYourSupporterKey": "Conecte sua chave de colaborador com at\u00e9 {0} membros do Media Browser Connect para desfrutar de acesso livre \u00e0s seguintes apps:",
+    "HeaderConfirmRemoveUser": "Remover Usu\u00e1rio",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Deseja realmente remover os benef\u00edcios adicionais de colaborador deste usu\u00e1rio?",
+    "ValueTimeLimitSingleHour": "Limite de tempo: 1 hora",
+    "ValueTimeLimitMultiHour": "Limite de tempo: {0} horas",
+    "HeaderUsers": "Usu\u00e1rios",
+    "PluginCategoryGeneral": "Geral",
+    "PluginCategoryContentProvider": "Provedores de Conte\u00fado",
+    "PluginCategoryScreenSaver": "Protetores de Tela",
+    "PluginCategoryTheme": "Temas",
+    "PluginCategorySync": "Sincroniza\u00e7\u00e3o",
+    "PluginCategorySocialIntegration": "Redes Sociais",
+    "PluginCategoryNotifications": "Notifica\u00e7\u00f5es",
+    "PluginCategoryMetadata": "Metadados",
+    "PluginCategoryLiveTV": "TV ao Vivo",
+    "PluginCategoryChannel": "Canais",
     "HeaderSearch": "Busca",
     "ValueDateCreated": "Data da cria\u00e7\u00e3o: {0}",
     "LabelArtist": "Artista",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Adicionar \u00e0 Cole\u00e7\u00e3o",
     "HeaderSelectCertificatePath": "Selecione o Caminho do Certificado",
     "ConfirmMessageScheduledTaskButton": "Esta opera\u00e7\u00e3o normalmente \u00e9 executada automaticamente como uma tarefa agendada. Tamb\u00e9m pode ser executada manualmente. Para configurar a tarefa agendada, veja:",
-    "HeaderSupporterBenefit": "A ades\u00e3o de colaborador fornece benef\u00edcios adicionais como acesso a plugins premium, canais de conte\u00fado da internet e mais. {0}Saiba mais{1}.",
+    "HeaderSupporterBenefit": "A ades\u00e3o de colaborador fornece benef\u00edcios adicionais como acesso a sincroniza\u00e7\u00e3o, plugins premium, canais de conte\u00fado da internet e mais. {0}Saiba mais{1}.",
     "LabelSyncNoTargetsHelp": "Parece que voc\u00ea n\u00e3o possui nenhuma app que suporta sincroniza\u00e7\u00e3o.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Bem Vindo ao Painel do Media Browser",
     "HeaderWelcomeToMediaBrowserWebClient": "Bem-vindo ao Cliente Web do Media Browser",
     "ButtonTakeTheTour": "Fa\u00e7a o tour",
     "HeaderWelcomeBack": "Bem-vindo novamente!",
+    "TitleSync": "Sinc",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Fa\u00e7a o tour para ver as novidades",
     "MessageNoSyncJobsFound": "Nenhuma tarefa de sincroniza\u00e7\u00e3o encontrada. Crie uma tarefa de sincroniza\u00e7\u00e3o usando os bot\u00f5es Sincroniza\u00e7\u00e3o encontrados na interface web.",
     "HeaderLibraryAccess": "Acesso \u00e0 Biblioteca",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} instalado",
     "LabelNumberReviews": "{0} Cr\u00edticas",
     "LabelFree": "Gr\u00e1tis",
+    "HeaderPlaybackError": "Erro na Reprodu\u00e7\u00e3o",
+    "MessagePlaybackErrorNotAllowed": "Voc\u00ea n\u00e3o est\u00e1 autorizado a reproduzir este conte\u00fado. Por favor, entre em contato com o administrador do sistema para mais detalhes.",
+    "MessagePlaybackErrorNoCompatibleStream": "N\u00e3o existem streams compat\u00edveis dispon\u00edveis. Por favor, tente novamente mais tarde.",
+    "MessagePlaybackErrorRateLimitExceeded": "Seu limite da taxa de reprodu\u00e7\u00e3o foi excedido. Por favor, entre em contato com o administrador do sistema para mais detalhes.",
     "HeaderSelectAudio": "Selecione \u00c1udio",
     "HeaderSelectSubtitles": "Selecione Legendas",
     "ButtonMarkForRemoval": "Remover do dispositivo",
     "ButtonUnmarkForRemoval": "Cancelar remo\u00e7\u00e3o do dispositivo",
-    "LabelSyncQualityHelp": "Use alta qualidade para usar a qualidade m\u00e1xima suportada pelo dispositivo. Qualidades m\u00e9dia e baixa reduzir\u00e3o a taxa permitida. Original sincronizar\u00e1 o arquivo original, independente se o dispositivo ser\u00e1 capaz de reproduzi-lo.",
     "LabelDefaultStream": "(Padr\u00e3o)",
     "LabelForcedStream": "(For\u00e7ada)",
     "LabelDefaultForcedStream": "(Padr\u00e3o\/For\u00e7ada)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Estr\u00e9ia {0}",
     "ValueStudio": "Est\u00fadio: {0}",
     "ValueStudios": "Est\u00fadios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Especial -  {0}",
     "LabelLimit": "Limite:",
     "ValueLinks": "Links: {0}",
@@ -640,7 +664,7 @@
     "WebClientTourMetadataManager": "Clique em editar para abrir o gerenciador de metadados",
     "WebClientTourPlaylists": "Crie listas de reprodu\u00e7\u00e3o e mixes instant\u00e2neos e reproduza-os em qualquer dispositivo",
     "WebClientTourCollections": "Crie cole\u00e7\u00f5es de filmes para agrupar colet\u00e2neas",
-    "WebClientTourUserPreferences1": "As prefer\u00eancias do usu\u00e1rio permite que voc\u00e9 personalize como sua biblioteca \u00e9 exibida em qualquer uma das apps do Media Browser",
+    "WebClientTourUserPreferences1": "As prefer\u00eancias do usu\u00e1rio permitem que voc\u00ea personalize como sua biblioteca \u00e9 exibida em qualquer uma das apps do Media Browser",
     "WebClientTourUserPreferences2": "Configure o idioma de \u00e1udio e legendas apenas uma vez, para todas as apps do Media Browser",
     "WebClientTourUserPreferences3": "Defina a p\u00e1gina de in\u00edcio do cliente web, do seu gosto",
     "WebClientTourUserPreferences4": "Configure imagens de fundo, m\u00fasicas-tema e reprodutores externos",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sincronizar",
     "SyncMedia": "Sincronizar M\u00eddia",
     "HeaderCancelSyncJob": "Cancelar Sincroniza\u00e7\u00e3o",
-    "CancelSyncJobConfirmation": "Deseja realmente cancelar esta tarefa de sincroniza\u00e7\u00e3o?",
+    "CancelSyncJobConfirmation": "Cancelar a tarefa de sincroniza\u00e7\u00e3o remover\u00e1 m\u00eddias sincronizadas do dispositivo durante o pr\u00f3ximo processo de sincroniza\u00e7\u00e3o. Deseja realmente proceder?",
     "TabSync": "Sincroniza\u00e7\u00e3o",
     "MessagePleaseSelectDeviceToSyncTo": "Por favor, selecione um dispositivo para sincronizar.",
     "MessageSyncJobCreated": "Tarefa de sincroniza\u00e7\u00e3o criada.",
     "LabelSyncTo": "Sincronizar para:",
     "LabelSyncJobName": "Nome da tarefa de sincroniza\u00e7\u00e3o:",
     "LabelQuality": "Qualidade:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "Alta",
-    "OptionMedium": "M\u00e9dia",
-    "OptionLow": "Baixa",
     "HeaderSettings": "Ajustes",
     "OptionAutomaticallySyncNewContent": "Sincronizar novo conte\u00fado automaticamente",
     "OptionAutomaticallySyncNewContentHelp": "Novo conte\u00fado adicionado a esta categoria ser\u00e1 automaticamente sincronizado com o dispositivo.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Sincronizado",
     "SyncJobItemStatusFailed": "Falhou",
     "SyncJobItemStatusRemovedFromDevice": "Removido do dispositivo",
-    "SyncJobItemStatusCancelled": "Cancelado"
+    "SyncJobItemStatusCancelled": "Cancelado",
+    "LabelProfile": "Perfil:",
+    "LabelBitrateMbps": "Taxa (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
index 8cc72f1b26..9bc831d5f2 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Utilizadores",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,13 +87,15 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
-    "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
-    "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
-    "ButtonTakeTheTour": "Take the tour",
+    "HeaderWelcomeToMediaBrowserServerDashboard": "Bem-vindo ao Painel Principal do Media Browser",
+    "HeaderWelcomeToMediaBrowserWebClient": "Bem-vindo ao cliente web do Media Browser",
+    "ButtonTakeTheTour": "Fa\u00e7a o tour",
     "HeaderWelcomeBack": "Welcome back!",
-    "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
+    "ButtonTakeTheTourToSeeWhatsNew": "Fa\u00e7a o tour para ver as novidades",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
     "HeaderChannelAccess": "Channel Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -263,7 +286,7 @@
     "MessageErrorPlayingVideo": "There was an error playing the video.",
     "MessageEnsureOpenTuner": "Please ensure there is an open tuner availalble.",
     "ButtonHome": "In\u00edcio",
-    "ButtonDashboard": "Dashboard",
+    "ButtonDashboard": "Painel Principal",
     "ButtonReports": "Reports",
     "ButtonMetadataManager": "Metadata Manager",
     "HeaderTime": "Time",
@@ -369,8 +392,8 @@
     "TabAdvanced": "Avan\u00e7ado",
     "TabHelp": "Help",
     "TabScheduledTasks": "Scheduled Tasks",
-    "ButtonFullscreen": "Fullscreen",
-    "ButtonAudioTracks": "Audio Tracks",
+    "ButtonFullscreen": "Ecr\u00e3 cheio",
+    "ButtonAudioTracks": "Faixas de \u00e1udio",
     "ButtonSubtitles": "Legendas",
     "ButtonScenes": "Cenas",
     "ButtonQuality": "Quality",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -585,7 +609,7 @@
     "HeaderAlbums": "Albums",
     "HeaderGames": "Games",
     "HeaderBooks": "Books",
-    "HeaderEpisodes": "Episodes",
+    "HeaderEpisodes": "Epis\u00f3dios",
     "HeaderSeasons": "Seasons",
     "HeaderTracks": "Tracks",
     "HeaderItems": "Items",
@@ -648,7 +672,7 @@
     "WebClientTourMobile2": "and easily controls other devices and Media Browser apps",
     "WebClientTourMySync": "Sync your personal media to your devices for offline viewing.",
     "MessageEnjoyYourStay": "Enjoy your stay",
-    "DashboardTourDashboard": "The server dashboard allows you to monitor your server and your users. You'll always know who is doing what and where they are.",
+    "DashboardTourDashboard": "O Painel Principal do servidor permite monitorizar o seu servidor e os seus utilizadores. Poder\u00e1 sempre saber onde est\u00e3o e o que est\u00e3o a fazer.",
     "DashboardTourHelp": "In-app help provides easy buttons to open wiki pages relating to the on-screen content.",
     "DashboardTourUsers": "Easily create user accounts for your friends and family, each with their own permissions, library access, parental controls and more.",
     "DashboardTourCinemaMode": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sincronizar",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
index 5ca071438e..3f1385a8f9 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
@@ -31,11 +31,29 @@
     "NoPluginsInstalledMessage": "\u041d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430.",
     "BrowsePluginCatalogMessage": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0438\u043c\u0435\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c\u0438.",
     "MessageKeyEmailedTo": "\u041a\u043b\u044e\u0447 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u042d-\u043f\u043e\u0447\u0442\u043e\u0439 \u043a {0}.",
-    "MessageKeysLinked": "\u041a\u043b\u044e\u0447\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u044b.",
+    "MessageKeysLinked": "\u041a\u043b\u044e\u0447\u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u044b.",
     "HeaderConfirmation": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435",
     "MessageKeyUpdated": "\u041a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0431\u044b\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d.",
     "MessageKeyRemoved": "\u041a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0431\u044b\u043b \u0443\u0434\u0430\u043b\u0451\u043d.",
     "ErrorLaunchingChromecast": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Chromecast. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0432\u0430\u0448\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u043a \u0431\u0435\u0441\u043f\u0440\u043e\u0432\u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0442\u0438.",
+    "MessageErrorLoadingSupporterInfo": "\u041f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0435. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.",
+    "MessageLinkYourSupporterKey": "\u0421\u0432\u044f\u0436\u0438\u0442\u0435 \u0432\u0430\u0448 \u043a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0441\u043e \u0432\u043f\u043b\u043e\u0442\u044c \u0434\u043e {0} \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 Media Browser Connect, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c:",
+    "HeaderConfirmRemoveUser": "\u0418\u0437\u044a\u044f\u0442\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
+    "MessageSwipeDownOnRemoteControl": "\u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043a \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u043c\u0443 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e. \u041f\u0440\u043e\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u043d\u0438\u0437 \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u0442\u0443\u0434\u0430, \u043e\u0442\u043a\u0443\u0434\u0430 \u0432\u044b \u043f\u0440\u0438\u0448\u043b\u0438.",
+    "MessageConfirmRemoveConnectSupporter": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0437\u044a\u044f\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f?",
+    "ValueTimeLimitSingleHour": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438: 1 \u0447\u0430\u0441",
+    "ValueTimeLimitMultiHour": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438: {0} \u0447\u0430\u0441(\u0430\/\u043e\u0432)",
+    "HeaderUsers": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438",
+    "PluginCategoryGeneral": "\u041e\u0431\u0449\u0438\u0435",
+    "PluginCategoryContentProvider": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f",
+    "PluginCategoryScreenSaver": "\u0425\u0440\u0430\u043d\u0438\u0442\u0435\u043b\u0438 \u044d\u043a\u0440\u0430\u043d\u0430",
+    "PluginCategoryTheme": "\u0422\u0435\u043c\u044b",
+    "PluginCategorySync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
+    "PluginCategorySocialIntegration": "\u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u0442\u0438",
+    "PluginCategoryNotifications": "\u0423\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f",
+    "PluginCategoryMetadata": "\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
+    "PluginCategoryLiveTV": "\u042d\u0444\u0438\u0440\u043d\u043e\u0435 \u0422\u0412",
+    "PluginCategoryChannel": "\u041a\u0430\u043d\u0430\u043b\u044b",
     "HeaderSearch": "\u041f\u043e\u0438\u0441\u043a",
     "ValueDateCreated": "\u0414\u0430\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f: {0}",
     "LabelArtist": "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c",
@@ -54,10 +72,10 @@
     "SyncJobStatusFailed": "\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u043e",
     "SyncJobStatusCancelled": "\u041e\u0442\u043c\u0435\u043d\u0435\u043d\u043e",
     "SyncJobStatusCompleted": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e",
-    "SyncJobStatusReadyToTransfer": "\u0413\u043e\u0442\u043e\u0432\u043e \u043a \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0443",
-    "SyncJobStatusTransferring": "\u041f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u0441\u044f",
+    "SyncJobStatusReadyToTransfer": "\u0413\u043e\u0442\u043e\u0432 \u043a \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0443",
+    "SyncJobStatusTransferring": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f",
     "SyncJobStatusCompletedWithError": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438",
-    "SyncJobItemStatusReadyToTransfer": "\u0413\u043e\u0442\u043e\u0432 \u043a \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0443",
+    "SyncJobItemStatusReadyToTransfer": "\u0413\u043e\u0442\u043e\u0432 \u043a \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0443",
     "LabelCollection": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f",
     "HeaderAddToCollection": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438",
     "NewCollectionNameExample": "\u041f\u0440\u0438\u043c\u0435\u0440: \u0417\u0432\u0451\u0437\u0434\u043d\u044b\u0435 \u0432\u043e\u0439\u043d\u044b (\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f)",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438",
     "HeaderSelectCertificatePath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u043a \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0443",
     "ConfirmMessageScheduledTaskButton": "\u042d\u0442\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043e\u0431\u044b\u0447\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u0430\u043a \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430. \u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043e\u0442\u0441\u044e\u0434\u0430. \u0427\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443, \u0441\u043c.:",
-    "HeaderSupporterBenefit": "\u0427\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u043e \u043f\u0440\u0435\u043c\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0438 \u043c\u043d\u043e\u0433\u043e\u043c\u0443 \u0434\u0440\u0443\u0433\u043e\u043c\u0443. {0}\u0423\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435{1}.",
+    "HeaderSupporterBenefit": "\u0427\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438, \u043f\u0440\u0435\u043c\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u043c, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043a\u0430\u043d\u0430\u043b\u043e\u0432 \u0438 \u043c\u043d\u043e\u0433\u043e\u043c\u0443 \u0434\u0440\u0443\u0433\u043e\u043c\u0443. {0}\u0423\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435{1}.",
     "LabelSyncNoTargetsHelp": "\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e, \u043d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u043c \u0432 \u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u0438 Media Browser",
     "HeaderWelcomeToMediaBrowserWebClient": "\u0412\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442 Media Browser \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0430\u0441!",
     "ButtonTakeTheTour": "\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f",
     "HeaderWelcomeBack": "\u0421 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435\u043c!",
+    "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
+    "TitlePlugins": "\u041f\u043b\u0430\u0433\u0438\u043d\u044b",
     "ButtonTakeTheTourToSeeWhatsNew": "\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u043e\u0432\u0430\u0446\u0438\u044f\u043c\u0438",
     "MessageNoSyncJobsFound": "\u0417\u0430\u0434\u0430\u043d\u0438\u0439 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043d\u043e\u043f\u043e\u043a \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443.",
     "HeaderLibraryAccess": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430: {0}",
     "LabelNumberReviews": "\u041e\u0442\u0437\u044b\u0432\u044b: {0}",
     "LabelFree": "\u0411\u0435\u0441\u043f\u043b.",
+    "HeaderPlaybackError": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
+    "MessagePlaybackErrorNotAllowed": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u044b \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f. \u0414\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
+    "MessagePlaybackErrorNoCompatibleStream": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.",
+    "MessagePlaybackErrorRateLimitExceeded": "\u0412\u0430\u0448\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0432\u044b\u0448\u0435\u043d\u0430. \u0414\u043b\u044f \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u0432\u0430\u0448\u0438\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u043c.",
     "HeaderSelectAudio": "\u0412\u044b\u0431\u043e\u0440 \u0430\u0443\u0434\u0438\u043e",
     "HeaderSelectSubtitles": "\u0412\u044b\u0431\u043e\u0440 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043e\u0432",
     "ButtonMarkForRemoval": "\u0418\u0437\u044a\u044f\u0442\u044c \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
     "ButtonUnmarkForRemoval": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0438\u0437\u044a\u044f\u0442\u0438\u0435 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
-    "LabelSyncQualityHelp": "\u0412\u044b\u0441\u043e\u043a\u043e\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e - \u043c\u0430\u043a\u0441., \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0443\u0441\u0442\u0440-\u043e\u043c. \u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0438 \u043d\u0438\u0437\u043a\u043e\u0435 - \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c. \u0418\u0441\u0445\u043e\u0434\u043d\u043e\u0435 - \u0441\u0438\u043d\u0445\u0440-\u0442\u0441\u044f \u043e\u0440\u0438\u0433-\u044b\u0439 \u0444\u0430\u0439\u043b.",
     "LabelDefaultStream": "(\u0423\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u0435)",
     "LabelForcedStream": "(\u0424\u043e\u0440\u0441-\u044b\u0435)",
     "LabelDefaultForcedStream": "(\u0423\u043c\u043e\u043b\u0447.\/\u0424\u043e\u0440\u0441-\u044b\u0435)",
@@ -208,7 +231,7 @@
     "StatusFailed": "\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u043e",
     "StatusSuccess": "\u0423\u0441\u043f\u0435\u0448\u043d\u043e",
     "MessageFileWillBeDeleted": "\u0411\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u0451\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b:",
-    "MessageSureYouWishToProceed": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?",
+    "MessageSureYouWishToProceed": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c?",
     "MessageDuplicatesWillBeDeleted": "\u0412 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0443\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0443\u0431\u043b\u0438\u043a\u0430\u0442\u044b:",
     "MessageFollowingFileWillBeMovedFrom": "\u0411\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0451\u043d \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0444\u0430\u0439\u043b \u0441:",
     "MessageDestinationTo": "\u043a:",
@@ -471,7 +494,7 @@
     "LabelContentTypeValue": "\u0422\u0438\u043f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f: {0}",
     "LabelPathSubstitutionHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u041f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0443\u0442\u0435\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u0441\u043e \u0441\u0435\u0442\u0435\u0432\u044b\u043c\u0438 \u043e\u0431\u0449\u0438\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0434\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f.",
     "FolderTypeUnset": "\u041d\u0435\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0439 (\u0440\u0430\u0437\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435)",
-    "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
+    "FolderTypeMovies": "\u041a\u0438\u043d\u043e",
     "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
     "FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
     "FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438",
@@ -511,7 +534,7 @@
     "MessagePendingMediaBrowserAccountAdded": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Media Browser \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042d-\u043f\u043e\u0447\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0443 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438. \u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c, \u0449\u0451\u043b\u043a\u043d\u0443\u0432 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u042d-\u043f\u043e\u0447\u0442\u0435.",
     "HeaderMediaBrowserAccountRemoved": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Media Browser \u0438\u0437\u044a\u044f\u0442\u0430",
     "MessageMediaBrowserAccontRemoved": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c Media Browser \u0431\u044b\u043b\u0430 \u0438\u0437\u044a\u044f\u0442\u0430 \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.",
-    "TooltipLinkedToMediaBrowserConnect": "\u0421\u0432\u044f\u0437\u044c \u0441 Media Browser Connect",
+    "TooltipLinkedToMediaBrowserConnect": "\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u044c \u0441 Media Browser Connect",
     "HeaderUnrated": "\u0411\u0435\u0437 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438",
     "ValueDiscNumber": "\u0414\u0438\u0441\u043a {0}",
     "HeaderUnknownDate": "\u041d\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u0430\u044f \u0434\u0430\u0442\u0430",
@@ -559,6 +582,7 @@
     "ValuePremieres": "\u041f\u0440\u0435\u043c\u044c\u0435\u0440\u0430 {0}",
     "ValueStudio": "\u0421\u0442\u0443\u0434\u0438\u044f: {0}",
     "ValueStudios": "\u0421\u0442\u0443\u0434\u0438\u0438: {0}",
+    "ValueStatus": "\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435: {0}",
     "ValueSpecialEpisodeName": "\u0421\u043f\u0435\u0446\u044d\u043f\u0438\u0437\u043e\u0434 - {0}",
     "LabelLimit": "\u041f\u0440\u0435\u0434\u0435\u043b:",
     "ValueLinks": "\u0421\u0441\u044b\u043b\u043a\u0438: {0}",
@@ -691,21 +715,17 @@
     "MessagePasswordResetForUsers": "\u041f\u0430\u0440\u043e\u043b\u0438 \u0431\u044b\u043b\u0438 \u0438\u0437\u044a\u044f\u0442\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:",
     "HeaderInviteGuest": "\u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u0433\u043e\u0441\u0442\u044f",
     "ButtonLinkMyMediaBrowserAccount": "\u0421\u0432\u044f\u0437\u0430\u0442\u044c \u043c\u043e\u044e \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c",
-    "MessageConnectAccountRequiredToInviteGuest": "\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0442\u044c \u0433\u043e\u0441\u0442\u0435\u0439, \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Media Browser \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.",
+    "MessageConnectAccountRequiredToInviteGuest": "\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0442\u044c \u0433\u043e\u0441\u0442\u0435\u0439, \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Media Browser \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.",
     "ButtonSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c",
     "SyncMedia": "\u0421\u0438\u043d\u0445\u0440-\u0438\u044f",
     "HeaderCancelSyncJob": "\u041e\u0442\u043c\u0435\u043d\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438",
-    "CancelSyncJobConfirmation": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438?",
+    "CancelSyncJobConfirmation": "\u041e\u0442\u043c\u0435\u043d\u0430 \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044e \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438. \u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c?",
     "TabSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
     "MessagePleaseSelectDeviceToSyncTo": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438.",
     "MessageSyncJobCreated": "\u0417\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u043e.",
     "LabelSyncTo": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0441:",
     "LabelSyncJobName": "\u0418\u043c\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440-\u0438\u0438:",
     "LabelQuality": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e:",
-    "OptionOriginal": "\u0418\u0441\u0445\u043e\u0434\u043d\u043e\u0435",
-    "OptionHigh": "\u0412\u044b\u0441\u043e\u043a\u043e\u0435",
-    "OptionMedium": "\u0421\u0440\u0435\u0434\u043d\u0435\u0435",
-    "OptionLow": "\u041d\u0438\u0437\u043a\u043e\u0435",
     "HeaderSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b",
     "OptionAutomaticallySyncNewContent": "\u0421\u0438\u043d\u0445\u0440-\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",
     "OptionAutomaticallySyncNewContentHelp": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0435 \u0432 \u044d\u0442\u0443 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e, \u0430\u0432\u0442\u043e-\u043a\u0438 \u0441\u0438\u043d\u0445\u0440-\u0442\u0441\u044f \u0441 \u0443\u0441\u0442\u0440-\u043e\u043c.",
@@ -718,9 +738,11 @@
     "MessageUnsetContentHelp": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438. \u0414\u043b\u044f \u043d\u0430\u0438\u043b\u0443\u0447\u0448\u0438\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u0442\u0438\u043f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0430\u043f\u043e\u043a.",
     "SyncJobItemStatusQueued": "\u0412 \u043e\u0447\u0435\u0440\u0435\u0434\u0438",
     "SyncJobItemStatusConverting": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f",
-    "SyncJobItemStatusTransferring": "\u041f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u0441\u044f",
+    "SyncJobItemStatusTransferring": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u0441\u044f",
     "SyncJobItemStatusSynced": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e",
     "SyncJobItemStatusFailed": "\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u043e",
     "SyncJobItemStatusRemovedFromDevice": "\u0418\u0437\u044a\u044f\u0442\u043e \u0438\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430",
-    "SyncJobItemStatusCancelled": "\u041e\u0442\u043c\u0435\u043d\u0435\u043d\u043e"
+    "SyncJobItemStatusCancelled": "\u041e\u0442\u043c\u0435\u043d\u0435\u043d\u043e",
+    "LabelProfile": "\u041f\u0440\u043e\u0444\u0438\u043b\u044c:",
+    "LabelBitrateMbps": "\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c (\u041c\u0431\u0438\u0442\/\u0441):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json
index f9ac9a7c04..46812271e8 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sl_SI.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Users",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Kvaliteta:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "Visoka",
-    "OptionMedium": "Srednja",
-    "OptionLow": "Nizka",
     "HeaderSettings": "Nastavitve",
     "OptionAutomaticallySyncNewContent": "Samodejno sinhroniziraj nove vsebine",
     "OptionAutomaticallySyncNewContentHelp": "Nova vsebina, dodana v to kategorijo, bo samodejno sinhronizirana v napravo",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
index 9dc1a8d7fa..212f9a3922 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Tack. Din donationskod har uppdaterats.",
     "MessageKeyRemoved": "Tack. Din donationskod har raderats.",
     "ErrorLaunchingChromecast": "Det gick inte att starta Chromecast. Kontrollera att enheten \u00e4r ansluten till det tr\u00e5dl\u00f6sa n\u00e4tverket.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Anv\u00e4ndare",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "S\u00f6k",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "V\u00e4lkommen till Media Browsers kontrollpanel",
     "HeaderWelcomeToMediaBrowserWebClient": "V\u00e4lkommen till Media Browsers webbklient",
     "ButtonTakeTheTour": "Ta en rundtur",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "Inga synkjobb hittades. Skapa synkjobb med hj\u00e4lp av Synk-knapparna som finns i hela gr\u00e4nssnittet.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installerade",
     "LabelNumberReviews": "{0} recensioner",
     "LabelFree": "Gratis",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "V\u00e4lj ljudsp\u00e5r",
     "HeaderSelectSubtitles": "V\u00e4lj undertexter",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(f\u00f6rvalda)",
     "LabelForcedStream": "(tvingade)",
     "LabelDefaultForcedStream": "(f\u00f6rvalda\/tvingade)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premi\u00e4rdatum {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studior: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Gr\u00e4ns:",
     "ValueLinks": "L\u00e4nkar: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Synk",
     "SyncMedia": "Synkronisera Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Synk",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Synkronisera automatiskt nytt inneh\u00e5ll",
     "OptionAutomaticallySyncNewContentHelp": "Nytt inneh\u00e5ll som l\u00e4ggs till i denna kategori kommer automatiskt synkroniseras till enheten.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synkad",
     "SyncJobItemStatusFailed": "Misslyckades",
     "SyncJobItemStatusRemovedFromDevice": "Borttagen fr\u00e5n enhet",
-    "SyncJobItemStatusCancelled": "Avbruten"
+    "SyncJobItemStatusCancelled": "Avbruten",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
index b8b512a8a2..867500c677 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "Kullan\u0131c\u0131lar",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json
index 153da991a1..33e3e5335a 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/uk.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u041a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0456",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "\u041f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -119,8 +142,8 @@
     "LabelEnabled": "Enabled",
     "LabelDisabled": "Disabled",
     "ButtonMoreInformation": "More Information",
-    "LabelNoUnreadNotifications": "No unread notifications.",
-    "ButtonViewNotifications": "View notifications",
+    "LabelNoUnreadNotifications": "\u041d\u0435\u043c\u0430\u0454 \u043d\u0435\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u0438\u0445 \u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u044c.",
+    "ButtonViewNotifications": "\u041f\u0435\u0440\u0435\u0433\u043b\u044f\u043d\u0443\u0442\u0438 \u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f",
     "ButtonMarkTheseRead": "Mark these read",
     "ButtonClose": "Close",
     "LabelAllPlaysSentToPlayer": "All plays will be sent to the selected player.",
@@ -173,10 +196,10 @@
     "HeaderResume": "Resume",
     "HeaderMyViews": "My Views",
     "HeaderLibraryFolders": "Media Folders",
-    "HeaderLatestMedia": "Latest Media",
+    "HeaderLatestMedia": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u043c\u0435\u0434\u0456\u0430",
     "ButtonMoreItems": "More...",
     "ButtonMore": "More",
-    "HeaderFavoriteMovies": "Favorite Movies",
+    "HeaderFavoriteMovies": "\u0423\u043b\u044e\u0431\u043b\u0435\u043d\u0456 \u0444\u0456\u043b\u044c\u043c\u0438",
     "HeaderFavoriteShows": "Favorite Shows",
     "HeaderFavoriteEpisodes": "Favorite Episodes",
     "HeaderFavoriteGames": "Favorite Games",
@@ -278,9 +301,9 @@
     "HeaderBlockItemsWithNoRating": "Block content with no rating information:",
     "OptionBlockOthers": "Others",
     "OptionBlockTvShows": "TV Shows",
-    "OptionBlockTrailers": "Trailers",
+    "OptionBlockTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u0438",
     "OptionBlockMusic": "Music",
-    "OptionBlockMovies": "Movies",
+    "OptionBlockMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "OptionBlockBooks": "Books",
     "OptionBlockGames": "Games",
     "OptionBlockLiveTvPrograms": "Live TV Programs",
@@ -328,7 +351,7 @@
     "OptionImages": "Images",
     "OptionKeywords": "Keywords",
     "OptionTags": "Tags",
-    "OptionStudios": "Studios",
+    "OptionStudios": "\u0421\u0442\u0443\u0434\u0456\u0457",
     "OptionName": "Name",
     "OptionOverview": "Overview",
     "OptionGenres": "Genres",
@@ -374,7 +397,7 @@
     "ButtonSubtitles": "Subtitles",
     "ButtonScenes": "Scenes",
     "ButtonQuality": "\u042f\u043a\u0456\u0441\u0442\u044c",
-    "HeaderNotifications": "Notifications",
+    "HeaderNotifications": "\u041f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f",
     "HeaderSelectPlayer": "Select Player:",
     "ButtonSelect": "Select",
     "ButtonNew": "\u041d\u043e\u0432\u0438\u0439",
@@ -392,7 +415,7 @@
     "ValueOriginalAirDate": "Original air date: {0}",
     "ButtonRemoveFromPlaylist": "Remove from playlist",
     "HeaderSpecials": "Specials",
-    "HeaderTrailers": "Trailers",
+    "HeaderTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u0438",
     "HeaderAudio": "\u0410\u0443\u0434\u0456\u043e",
     "HeaderResolution": "Resolution",
     "HeaderVideo": "\u0412\u0456\u0434\u0435\u043e",
@@ -411,8 +434,8 @@
     "HeaderEmbeddedImage": "Embedded image",
     "HeaderTrack": "\u0414\u043e\u0440\u0456\u0436\u043a\u0430",
     "HeaderDisc": "\u0414\u0438\u0441\u043a",
-    "OptionMovies": "Movies",
-    "OptionCollections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u044f",
+    "OptionMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
+    "OptionCollections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u0457",
     "OptionSeries": "\u0421\u0435\u0440\u0456\u044f",
     "OptionSeasons": "\u0421\u0435\u0437\u043e\u043d\u0438",
     "OptionEpisodes": "Episodes",
@@ -471,7 +494,7 @@
     "LabelContentTypeValue": "Content type: {0}",
     "LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
     "FolderTypeUnset": "Unset (mixed content)",
-    "FolderTypeMovies": "Movies",
+    "FolderTypeMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "FolderTypeMusic": "\u041c\u0443\u0437\u0438\u043a\u0430",
     "FolderTypeAdultVideos": "Adult videos",
     "FolderTypePhotos": "\u0421\u0432\u0456\u0442\u043b\u0438\u043d\u0438",
@@ -480,10 +503,10 @@
     "FolderTypeGames": "\u0406\u0433\u0440\u0438",
     "FolderTypeBooks": "\u041a\u043d\u0438\u0433\u0438",
     "FolderTypeTvShows": "\u0422\u0411",
-    "TabMovies": "Movies",
+    "TabMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "TabSeries": "Series",
     "TabEpisodes": "\u0415\u043f\u0456\u0437\u043e\u0434\u0438",
-    "TabTrailers": "Trailers",
+    "TabTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u0438",
     "TabGames": "Games",
     "TabAlbums": "Albums",
     "TabSongs": "Songs",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "\u0421\u0442\u0443\u0434\u0456\u044f: {0}",
     "ValueStudios": "\u0421\u0442\u0443\u0434\u0456\u0457: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "\u041e\u0431\u043c\u0435\u0436\u0435\u043d\u043d\u044f:",
     "ValueLinks": "\u041f\u043e\u0441\u0438\u043b\u0430\u043d\u043d\u044f: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0456\u0437\u043e\u0432\u0430\u043d\u043e",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "\u0421\u043a\u0430\u0441\u043e\u0432\u0430\u043d\u043e"
+    "SyncJobItemStatusCancelled": "\u0421\u043a\u0430\u0441\u043e\u0432\u0430\u043d\u043e",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
index 2589645d49..85e6f730d7 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "d\u00f9ng",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
index 40e2fa6b1f..0afd39eea8 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "\u8c22\u8c22\u3002\u4f60\u7684\u652f\u6301\u8005\u5e8f\u53f7\u5df2\u66f4\u65b0\u3002",
     "MessageKeyRemoved": "\u8c22\u8c22\u3002\u4f60\u7684\u652f\u6301\u8005\u5e8f\u53f7\u5df2\u79fb\u9664\u3002",
     "ErrorLaunchingChromecast": "\u542f\u52a8chromecast\u9047\u5230\u9519\u8bef\uff0c\u8bf7\u786e\u8ba4\u8bbe\u5907\u5df2\u7ecf\u8fde\u63a5\u5230\u4f60\u7684\u65e0\u7ebf\u7f51\u7edc\u3002",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u7528\u6237",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "\u641c\u7d22",
     "ValueDateCreated": "\u521b\u5efa\u65e5\u671f\uff1a {0}",
     "LabelArtist": "\u827a\u672f\u5bb6",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "\u6dfb\u52a0\u5230\u6536\u85cf",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "\u6b64\u64cd\u4f5c\u901a\u5e38\u662f\u901a\u8fc7\u8ba1\u5212\u4efb\u52a1\u81ea\u52a8\u8fd0\u884c\u3002\u5b83\u4e5f\u53ef\u624b\u52a8\u8fd0\u884c\u3002\u8981\u914d\u7f6e\u8ba1\u5212\u4efb\u52a1\uff0c\u8bf7\u53c2\u9605\uff1a",
-    "HeaderSupporterBenefit": "\u652f\u6301\u8005\u4f1a\u5458\u4f1a\u5f97\u5230\u989d\u5916\u7684\u597d\u5904\uff0c\u5982\u83b7\u5f97\u9ad8\u7ea7\u63d2\u4ef6\uff0c\u4e92\u8054\u7f51\u9891\u9053\u5185\u5bb9\uff0c\u7b49\u7b49\u3002{0}\u4e86\u89e3\u8be6\u60c5{1} \u3002",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "\u6b22\u8fce\u6765\u5230Media Browser\u63a7\u5236\u53f0",
     "HeaderWelcomeToMediaBrowserWebClient": "\u6b22\u8fce\u8fdb\u5165Media Browser Web\u5ba2\u6237\u7aef",
     "ButtonTakeTheTour": "\u8fdb\u884c\u53c2\u89c2",
     "HeaderWelcomeBack": "\u6b22\u8fce\u56de\u6765\uff01",
+    "TitleSync": "\u540c\u6b65",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "\u8fdb\u884c\u53c2\u89c2\uff0c\u770b\u770b\u6709\u4ec0\u4e48\u65b0\u4e1c\u897f",
     "MessageNoSyncJobsFound": "\u6ca1\u6709\u53d1\u73b0\u540c\u6b65\u4f5c\u4e1a\u3002\u4f7f\u7528Web\u754c\u9762\u4e2d\u7684\u540c\u6b65\u6309\u94ae\u6765\u521b\u5efa\u540c\u6b65\u4f5c\u4e1a\u3002",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} \u5df2\u5b89\u88c5",
     "LabelNumberReviews": "{0} \u8bc4\u8bba",
     "LabelFree": "\u514d\u8d39",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "\u9009\u62e9\u97f3\u9891",
     "HeaderSelectSubtitles": "\u9009\u62e9\u5b57\u5e55",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(\u9ed8\u8ba4)",
     "LabelForcedStream": "(\u5f3a\u5236)",
     "LabelDefaultForcedStream": "(\u9ed8\u8ba4\/\u5f3a\u5236)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "\u9996\u6620 {0}",
     "ValueStudio": "\u5de5\u4f5c\u5ba4\uff1a {0}",
     "ValueStudios": "\u5de5\u4f5c\u5ba4\uff1a {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "\u7279\u522b - {0}",
     "LabelLimit": "\u9650\u5236\uff1a",
     "ValueLinks": "\u94fe\u63a5\uff1a {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "\u540c\u6b65",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "\u540c\u6b65",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
index 2cf926942c..6afd967d37 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
@@ -36,6 +36,24 @@
     "MessageKeyUpdated": "Thank you. Your supporter key has been updated.",
     "MessageKeyRemoved": "Thank you. Your supporter key has been removed.",
     "ErrorLaunchingChromecast": "There was an error launching chromecast. Please ensure your device is connected to your wireless network.",
+    "MessageErrorLoadingSupporterInfo": "There was an error loading supporter information. Please try again later.",
+    "MessageLinkYourSupporterKey": "Link your supporter key with up to {0} Media Browser Connect members to enjoy free access to the following apps:",
+    "HeaderConfirmRemoveUser": "Remove User",
+    "MessageSwipeDownOnRemoteControl": "Welcome to remote control. Swipe down anywhere on this screen to go back to where you came from.",
+    "MessageConfirmRemoveConnectSupporter": "Are you sure you wish to remove additional supporter benefits from this user?",
+    "ValueTimeLimitSingleHour": "Time limit: 1 hour",
+    "ValueTimeLimitMultiHour": "Time limit: {0} hours",
+    "HeaderUsers": "\u7528\u6236",
+    "PluginCategoryGeneral": "General",
+    "PluginCategoryContentProvider": "Content Providers",
+    "PluginCategoryScreenSaver": "Screen Savers",
+    "PluginCategoryTheme": "Themes",
+    "PluginCategorySync": "Sync",
+    "PluginCategorySocialIntegration": "Social Networks",
+    "PluginCategoryNotifications": "Notifications",
+    "PluginCategoryMetadata": "Metadata",
+    "PluginCategoryLiveTV": "Live TV",
+    "PluginCategoryChannel": "Channels",
     "HeaderSearch": "Search",
     "ValueDateCreated": "Date created: {0}",
     "LabelArtist": "Artist",
@@ -69,12 +87,14 @@
     "ButtonAddToCollection": "Add to collection",
     "HeaderSelectCertificatePath": "Select Certificate Path",
     "ConfirmMessageScheduledTaskButton": "This operation normally runs automatically as a scheduled task. It can also be run manually here. To configure the scheduled task, see:",
-    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more. {0}Learn more{1}.",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to sync, premium plugins, internet channel content, and more. {0}Learn more{1}.",
     "LabelSyncNoTargetsHelp": "It looks like you don't currently have any apps that support sync.",
     "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
     "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
     "ButtonTakeTheTour": "Take the tour",
     "HeaderWelcomeBack": "Welcome back!",
+    "TitleSync": "Sync",
+    "TitlePlugins": "Plugins",
     "ButtonTakeTheTourToSeeWhatsNew": "Take the tour to see what's new",
     "MessageNoSyncJobsFound": "No sync jobs found. Create sync jobs using the Sync buttons found throughout the web interface.",
     "HeaderLibraryAccess": "Library Access",
@@ -95,11 +115,14 @@
     "LabelVersionInstalled": "{0} installed",
     "LabelNumberReviews": "{0} Reviews",
     "LabelFree": "Free",
+    "HeaderPlaybackError": "Playback Error",
+    "MessagePlaybackErrorNotAllowed": "You're currently not authorized to play this content. Please contact your system administrator for details.",
+    "MessagePlaybackErrorNoCompatibleStream": "No compatible streams are currently available. Please try again later.",
+    "MessagePlaybackErrorRateLimitExceeded": "Your playback rate limit has been exceeded. Please contact your system administrator for details.",
     "HeaderSelectAudio": "Select Audio",
     "HeaderSelectSubtitles": "Select Subtitles",
     "ButtonMarkForRemoval": "Remove from device",
     "ButtonUnmarkForRemoval": "Cancel removal from device",
-    "LabelSyncQualityHelp": "Use high quality for the maximum supported quality by the device. Medium and low quality will reduce the allowed bitrate. Original will sync the original file, regardless of whether the device is capable of playing it or not.",
     "LabelDefaultStream": "(Default)",
     "LabelForcedStream": "(Forced)",
     "LabelDefaultForcedStream": "(Default\/Forced)",
@@ -559,6 +582,7 @@
     "ValuePremieres": "Premieres {0}",
     "ValueStudio": "Studio: {0}",
     "ValueStudios": "Studios: {0}",
+    "ValueStatus": "Status: {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "LabelLimit": "Limit:",
     "ValueLinks": "Links: {0}",
@@ -695,17 +719,13 @@
     "ButtonSync": "Sync",
     "SyncMedia": "Sync Media",
     "HeaderCancelSyncJob": "Cancel Sync",
-    "CancelSyncJobConfirmation": "Are you sure you wish to cancel this sync job?",
+    "CancelSyncJobConfirmation": "Cancelling the sync job will remove synced media from the device during the next sync process. Are you sure you wish to proceed?",
     "TabSync": "Sync",
     "MessagePleaseSelectDeviceToSyncTo": "Please select a device to sync to.",
     "MessageSyncJobCreated": "Sync job created.",
     "LabelSyncTo": "Sync to:",
     "LabelSyncJobName": "Sync job name:",
     "LabelQuality": "Quality:",
-    "OptionOriginal": "Original",
-    "OptionHigh": "High",
-    "OptionMedium": "Medium",
-    "OptionLow": "Low",
     "HeaderSettings": "Settings",
     "OptionAutomaticallySyncNewContent": "Automatically sync new content",
     "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.",
@@ -722,5 +742,7 @@
     "SyncJobItemStatusSynced": "Synced",
     "SyncJobItemStatusFailed": "Failed",
     "SyncJobItemStatusRemovedFromDevice": "Removed from device",
-    "SyncJobItemStatusCancelled": "Cancelled"
+    "SyncJobItemStatusCancelled": "Cancelled",
+    "LabelProfile": "Profile:",
+    "LabelBitrateMbps": "Bitrate (Mbps):"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
index d94fff9dda..542d677215 100644
--- a/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
+++ b/MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
@@ -374,6 +374,7 @@ namespace MediaBrowser.Server.Implementations.Localization
                 new LocalizatonOption{ Name="German", Value="de"},
                 new LocalizatonOption{ Name="Greek", Value="el"},
                 new LocalizatonOption{ Name="Hebrew", Value="he"},
+                new LocalizatonOption{ Name="Hungarian", Value="hu"},
                 new LocalizatonOption{ Name="Italian", Value="it"},
                 new LocalizatonOption{ Name="Kazakh", Value="kk"},
                 new LocalizatonOption{ Name="Norwegian Bokmål", Value="nb"},
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ar.json b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
index 07628944c9..01969cbb14 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "\u0645\u0648\u0627\u0641\u0642",
     "ButtonCancel": "\u0627\u0644\u063a\u0627\u0621",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u0627\u0644\u0631\u062c\u0648\u0639 \u0627\u0644\u0649 wiki \u0644\u0645\u0643\u062a\u0628\u0629 \u0627\u0644\u0648\u0633\u0627\u0626\u0637",
     "LabelCountry": "\u0627\u0644\u0628\u0644\u062f:",
     "LabelLanguage": "\u0627\u0644\u0644\u063a\u0629:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "\u0627\u0644\u0644\u063a\u0629 \u0627\u0644\u0645\u0641\u0636\u0644\u0629 \u0644\u0648\u0627\u0635\u0641\u0627\u062a \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a:",
     "LabelSaveLocalMetadata": "\u062d\u0641\u0638 \u0627\u0644\u0627\u0639\u0645\u0627\u0644 \u0627\u0644\u0641\u0646\u064a\u0629 \u0648\u0648\u0627\u0635\u0641\u0627\u062a \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0641\u0649 \u0645\u062c\u0644\u062f\u0627\u062a \u0627\u0644\u0648\u0633\u0627\u0626\u0637",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "\u062c\u062f\u0648\u0644\u0629 \u0627\u0644\u0645\u0647\u0627\u0645",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json b/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json
index 743e5e2a64..417a31f9f3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/bg_BG.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "\u0410\u043a\u043e \u043f\u0443\u0441\u043a\u0430\u0442\u0435 \u0441\u044a\u0440\u0432\u044a\u0440\u0430 \u043e\u0442 \u0438\u0437\u0445\u043e\u0434\u0435\u043d \u043a\u043e\u0434, \u043f\u043e\u0441\u043e\u0447\u0435\u0442\u0435 \u043f\u044a\u0442\u044f \u043a\u044a\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0442\u043e \u0442\u0430\u0431\u043b\u043e. \u0412\u0441\u0438\u0447\u043a\u0438 \u0443\u0435\u0431 \u043a\u043b\u0438\u0435\u043d\u0442\u0438 \u0449\u0435 \u0431\u044a\u0434\u0430\u0442 \u043e\u0431\u0441\u043b\u0443\u0436\u0432\u0430\u043d\u0438 \u043e\u0442 \u0442\u0430\u043c.",
     "ButtonConvertMedia": "\u041a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0430\u0439 \u043c\u0435\u0434\u0438\u044f\u0442\u0430",
     "ButtonOrganize": "\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0438\u0440\u0430\u0439",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "\u041e\u043a",
     "ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0438",
+    "ButtonExit": "Exit",
     "ButtonNew": "\u041d\u043e\u0432",
     "HeaderTV": "TV",
     "HeaderAudio": "\u0410\u0443\u0434\u0438\u043e",
     "HeaderVideo": "\u0412\u0438\u0434\u0435\u043e",
     "HeaderPaths": "\u041f\u044a\u0442\u0438\u0449\u0430",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "\u0410\u043a\u043e \u0435 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0430\u043d\u043e, \u0444\u0430\u0439\u043b\u043e\u0432\u0435 \u0441 \u0440\u0430\u0437\u0448\u0438\u0440\u0435\u043d\u0438\u044f .rar \u0438 .zip \u0449\u0435 \u0431\u044a\u0434\u0430\u0442 \u0440\u0430\u0437\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438 \u043a\u0430\u0442\u043e \u043c\u0435\u0434\u0438\u0439\u043d\u0438 \u0444\u0430\u0439\u043b\u043e\u0432\u0435.",
     "LabelEnterConnectUserName": "\u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435 \u0438\u043b\u0438 email:",
     "LabelEnterConnectUserNameHelp": "\u0422\u043e\u0432\u0430 \u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e\u0442\u043e \u0438\u043c\u0435 \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u0430\u0442\u0430 \u043d\u0430 \u0432\u0430\u0448\u0438\u044f Media Brower \u043e\u043d\u043b\u0430\u0439\u043d \u0430\u043a\u0430\u0443\u043d\u0442.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "\u0421\u0438\u043d\u0445\u0440. \u0417\u0430\u0434\u0430\u0447\u0430",
     "FolderTypeMixed": "\u0421\u043c\u0435\u0441\u0435\u043d\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435",
     "FolderTypeMovies": "\u0424\u0438\u043b\u043c\u0438",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u0414\u043e\u043f\u0438\u0442\u0430\u0439\u0442\u0435 \u0441\u0435 \u0434\u043e wiki \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0442\u0430 \u043d\u0430 \u043c\u0435\u0434\u0438\u0439\u043d\u0430\u0442\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430",
     "LabelCountry": "\u0421\u0442\u0440\u0430\u043d\u0430:",
     "LabelLanguage": "\u0415\u0437\u0438\u043a:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "\u041f\u0440\u0438\u0441\u044a\u0435\u0434\u0438\u043d\u0435\u0442\u0435 \u0441\u0435 \u043a\u044a\u043c \u043e\u0442\u0431\u043e\u0440\u0430 \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u0446\u0438\u0442\u0435",
     "HeaderPreferredMetadataLanguage": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u043d \u0435\u0437\u0438\u043a \u043d\u0430 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f\u0442\u0430:",
     "LabelSaveLocalMetadata": "\u0417\u0430\u043f\u043e\u043c\u043d\u0438 \u0438\u0437\u043a\u0443\u0441\u0442\u0432\u043e \u0438 \u043c\u0435\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432 \u043f\u0430\u043f\u043a\u0430\u0442\u0430 \u043d\u0430 \u043c\u0435\u0434\u0438\u044f\u0442\u0430",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "\u041f\u043b\u0430\u043d\u0438\u0440\u0430\u043d\u0438 \u0417\u0430\u0434\u0430\u0447\u0438",
     "TabMyPlugins": "\u041c\u043e\u0438\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438",
     "TabCatalog": "\u041a\u0430\u0442\u0430\u043b\u043e\u0433",
-    "PluginsTitle": "\u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u0438 \u0412\u044a\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f",
     "HeaderNowPlaying": "\u0421\u0435\u0433\u0430 \u0412\u044a\u0437\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u043e:",
     "HeaderLatestAlbums": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438 \u0410\u043b\u0431\u0443\u043c\u0438",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u0422V \u043d\u0430 \u0436\u0438\u0432\u043e",
     "LabelNumberOfGuideDays": "\u0411\u0440\u043e\u0439 \u0434\u043d\u0438 \u0437\u0430 \u043a\u043e\u0438\u0442\u043e \u0434\u0430 \u0441\u0435 \u0441\u0432\u0430\u043b\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430:",
     "LabelNumberOfGuideDaysHelp": "\u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435\u0442\u043e \u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430 \u0437\u0430\u043f\u043e\u0432\u0435\u0447\u0435 \u0434\u043d\u0438 \u0434\u0430\u0432\u0430 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u0434\u0430 \u043f\u043b\u0430\u043d\u0438\u0440\u0430\u0442\u0435 \u043f\u043e-\u043d\u0430\u0442\u0430\u0442\u044a\u0448\u043d\u0438\u0442\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u043d\u043e, \u043d\u043e \u0438 \u043e\u0442\u043d\u0435\u043c\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u0432\u0440\u0435\u043c\u0435, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0442\u0435\u0433\u043b\u0438. \u0410\u0432\u0442\u043e\u043c\u0430\u0442  \u0449\u0435 \u0438\u0437\u0431\u0435\u0440\u0435 \u0432\u044a\u0437 \u043e\u0441\u043d\u043e\u0432\u0430 \u043d\u0430 \u0431\u0440\u043e\u044f \u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0438\u0442\u0435.",
-    "LabelActiveService": "\u0410\u043a\u0442\u0438\u0432\u043d\u0430 \u0423\u0441\u043b\u0443\u0433\u0430:",
-    "LabelActiveServiceHelp": "\u041d\u044f\u043a\u043e\u043b\u043a\u043e TV \u0434\u043e\u0431\u0430\u0432\u043a\u0438 \u043c\u043e\u0433\u0430\u0442 \u0434\u0430 \u0431\u044a\u0434\u0430\u0442 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0438, \u043d\u043e \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0431\u044a\u0434\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u043d\u0430 \u043f\u043e \u0435\u0434\u043d\u043e \u0438 \u0441\u044a\u0449\u043e \u0432\u0440\u0435\u043c\u0435.",
     "OptionAutomatic": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "\u041d\u0435\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0435 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430 \u0437\u0430 \u0433\u043b\u0435\u0434\u0430\u043d\u0435 \u043d\u0430 \u0442\u0435\u043b\u0435\u0432\u0438\u0437\u0438\u044f \u043d\u0430 \u0436\u0438\u0432\u043e, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u043f\u0440\u043e\u0434\u044a\u043b\u0436\u0438.",
     "LiveTvPluginRequiredHelp": "\u041c\u043e\u043b\u044f, \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u0439\u0442\u0435 \u043d\u044f\u043a\u043e\u044f \u043e\u0442 \u043d\u0430\u043b\u0438\u0447\u043d\u0438\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438, \u043a\u0430\u0442\u043e \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 Next Pvr \u0438\u043b\u0438 ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "\u041f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u0437\u0430 \u0442\u0438\u043f \u043c\u0435\u0434\u0438\u044f:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ca.json b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
index 71d51e1f4d..70c6262197 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/cs.json b/MediaBrowser.Server.Implementations/Localization/Server/cs.json
index 14b0e44604..f39c650c73 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/cs.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Zru\u0161it",
+    "ButtonExit": "Exit",
     "ButtonNew": "Nov\u00e9",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Pod\u00edvejte se na wiki knihovny m\u00e9di\u00ed.",
     "LabelCountry": "Zem\u011b:",
     "LabelLanguage": "Jazyk:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferovan\u00fd jazyk metadat:",
     "LabelSaveLocalMetadata": "Ulo\u017eit p\u0159ebaly a metadata do slo\u017eky s m\u00e9dii",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Rozvrh \u00faloh",
     "TabMyPlugins": "Moje pluginy",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Pluginy",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatick\u00e9 aktualizace",
     "HeaderNowPlaying": "Pr\u00e1v\u011b hraje",
     "HeaderLatestAlbums": "Posledn\u00ed alba",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u017div\u00e1 TV",
     "LabelNumberOfGuideDays": "Po\u010det dn\u016f pro sta\u017een\u00ed dat pr\u016fvodce:",
     "LabelNumberOfGuideDaysHelp": "Sta\u017een\u00edm v\u00edce dn\u016f dat pr\u016fvodce umo\u017en\u00ed v pl\u00e1nech nastavit budouc\u00ed nahr\u00e1v\u00e1n\u00ed v\u00edce do budoucna. M\u016f\u017ee v\u0161ak d\u00e9le trvat sta\u017een\u00ed t\u011bchto dat. Auto vybere mo\u017enost podle po\u010dtu kan\u00e1l\u016f.",
-    "LabelActiveService": "Aktivn\u00ed slu\u017eby:",
-    "LabelActiveServiceHelp": "M\u016f\u017ee b\u00fdt nainstalov\u00e1no v\u00edce plugin\u016f pro TV, ale jen jeden m\u016f\u017ee b\u00fdt aktivn\u00ed.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "P\u0159ed pokra\u010dov\u00e1n\u00edm je vy\u017eadov\u00e1n plugin TV poskytovatele.",
     "LiveTvPluginRequiredHelp": "Pros\u00edm nainstalujte jeden z dostupn\u00fdch plugin\u016f, jako Next PVR nebo ServerWmc",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Je vy\u017eadov\u00e1n restart serveru",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Filmy",
     "ViewTypeTvShows": "Televize",
     "ViewTypeGames": "Hry",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/da.json b/MediaBrowser.Server.Implementations/Localization/Server/da.json
index 642bb5266c..a6b8560f1e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/da.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Annuller",
+    "ButtonExit": "Exit",
     "ButtonNew": "Ny",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Der henvises til medie bibliotekets wiki.",
     "LabelCountry": "Land:",
     "LabelLanguage": "Sprog:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Foretrukket metadata sprog:",
     "LabelSaveLocalMetadata": "Gem illustrationer og metadata i medie mapper",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Planlagte Opgaver",
     "TabMyPlugins": "Mine Tilf\u00f8jelser",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Tilf\u00f8jelser",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatisk Opdateringer",
     "HeaderNowPlaying": "Afspilles Nu",
     "HeaderLatestAlbums": "Seneste Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Direkte TV",
     "LabelNumberOfGuideDays": "Antal dage af program guide data til download:",
     "LabelNumberOfGuideDaysHelp": "Hentning af flere dages program guide data giver mulighed for at planl\u00e6gge l\u00e6ngere ud i fremtiden, og se flere programoversigter, men det vil ogs\u00e5 tage l\u00e6ngere tid at downloade. Auto vil v\u00e6lge baseret p\u00e5 antallet af kanaler.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "Nyt indhold tilf\u00f8jet (flere)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/de.json b/MediaBrowser.Server.Implementations/Localization/Server/de.json
index 31d01cdc3e..260338676a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/de.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "Spezifiziere den Pfad zum Dashboard-UI-Verzeichniss, falls der Server von der Source ausgef\u00fchrt wird. Alle Web-Client-Dateien werden von diesem Pfad aus bedient werden.",
     "ButtonConvertMedia": "Konvertiere Medien",
     "ButtonOrganize": "Organisieren",
+    "LinkedToMediaBrowserConnect": "Verkn\u00fcpft mit Media Browser Connect",
+    "HeaderSupporterBenefits": "Unterst\u00fctzer Vorteile",
+    "HeaderAddUser": "Benutzer hinzuf\u00fcgen",
+    "LabelAddConnectSupporterHelp": "Um einen Benutzer hinzuzuf\u00fcgen, der nicht gelistet ist, m\u00fcssen Sie dessen Benutzerkonto erst \u00fcber sein Benutzerprofil mit Media Browser Connect verkn\u00fcpfen.",
+    "LabelPinCode": "PIN Code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Abbrechen",
+    "ButtonExit": "Exit",
     "ButtonNew": "Neu",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Pfade",
     "CategorySync": "Synchronisieren",
+    "TabPlaylist": "Wiedergabeliste",
     "HeaderEasyPinCode": "Einfacher PIN Code",
+    "HeaderGrownupsOnly": "Nur Erwachsene!",
+    "DividerOr": "-- oder --",
+    "HeaderInstalledServices": "Installierte Dienste",
+    "HeaderAvailableServices": "Verf\u00fcgbare Dienste",
+    "MessageNoServicesInstalled": "Keine Dienste installiert.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "Bitte geben Sie Ihren vereinfachten PIN Code ein:",
+    "KidsModeAdultInstruction": "Verwenden Sie das Schloss-Symbol in der rechten oberen Ecke um den Kindermodus zu verlassen oder zu konfigurieren. Sie ben\u00f6tigen daf\u00fcr Ihren PIN Code.",
+    "ButtonConfigurePinCode": "PIN Code festlegen",
+    "HeaderAdultsReadHere": "Eltern, bitte lesen!",
     "RegisterWithPayPal": "Registrieren mit PayPal",
     "HeaderSyncRequiresSupporterMembership": "Synchronisation ben\u00f6tigt eine Supporter-Mitgliedschaft",
     "HeaderEnjoyDayTrial": "Genie\u00dfen Sie eine 14 Tage Testversion",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "Wenn aktiviert werden .rar und .zip Datei-Erweiterungen wie Medien behandelt.",
     "LabelEnterConnectUserName": "Benutzername oder Email:",
     "LabelEnterConnectUserNameHelp": "Dies ist Ihr online Media Browser Benutzername oder Passwort.",
+    "LabelEnableEnhancedMovies": "Aktiviere erweiterte Filmdarstellung.",
+    "LabelEnableEnhancedMoviesHelp": "Wenn aktiviert, werden Filme als Verzeichnisse dargestellt, welche Trailer, Extras, Besetzung & Crew sowie weitere Inhalte enth\u00e4lt.",
     "HeaderSyncJobInfo": "Synchronisations-Aufgabe",
     "FolderTypeMixed": "Gemischte Inhalte",
     "FolderTypeMovies": "Filme",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Siehe die Medienbibliothek Wiki",
     "LabelCountry": "Land:",
     "LabelLanguage": "Sprache:",
+    "LabelTimeLimitHours": "Zeitlimit (Stunden):",
     "ButtonJoinTheDevelopmentTeam": "Schlie\u00dfen Sie sich dem Entwickler-Team an",
     "HeaderPreferredMetadataLanguage": "Bevorzugte Metadata Sprache:",
     "LabelSaveLocalMetadata": "Speichere Bildmaterial und Metadaten in den Medienverzeichnissen",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Geplante Aufgaben",
     "TabMyPlugins": "Meine Plugins",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatische Updates",
     "HeaderNowPlaying": "Aktuelle Wiedergabe",
     "HeaderLatestAlbums": "Neueste Alben",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live-TV",
     "LabelNumberOfGuideDays": "Anzahl von Tagen f\u00fcr die Programminformationen geladen werden sollen:",
     "LabelNumberOfGuideDaysHelp": "Das laden von zus\u00e4tzlichen Programmdaten bietet einen besseren \u00dcberblick und die M\u00f6glichkeit weiter in die Zukunft zu planen. Aber es wird l\u00e4nger dauern alles herunterzuladen. Auto w\u00e4hlt auf Grundlage der Kanalanzahl.",
-    "LabelActiveService": "Aktiver Service:",
-    "LabelActiveServiceHelp": "Mehrere TV Plugins k\u00f6nnen installiert sein, aber nur eines kann aktiv sein.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Dienste",
     "LiveTvPluginRequired": "Ein Live-TV Serviceproviderplugin ist notwendig um fortzufahren.",
     "LiveTvPluginRequiredHelp": "Bitte installiere eines der verf\u00fcgbaren Plugins, wie z.B. Next Pvr oder ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Anpassungen f\u00fcr Medientyp:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugef\u00fcgt",
     "NotificationOptionNewLibraryContentMultiple": "Neuen Inhalte hinzugef\u00fcgt (mehrere)",
     "NotificationOptionCameraImageUploaded": "Kamera Bild hochgeladen",
-    "SendNotificationHelp": "Standardm\u00e4\u00dfig werden Benachrichtigungen in der Optionsleiste angezeigt. Durchsuche den Plugin Katalog f\u00fcr die Installation von weiteren Benachrichtigungsm\u00f6glichkeiten.",
+    "NotificationOptionUserLockedOut": "Benutzer ausgeschlossen",
+    "HeaderSendNotificationHelp": "Standardm\u00e4\u00dfig werden Benachrichtigungen im Dashboard angezeigt. St\u00f6bern Sie im Plugin-Katalog um weitere Benachrichtigungsm\u00f6glichkeiten zu erhalten.",
     "NotificationOptionServerRestartRequired": "Serverneustart notwendig",
     "LabelNotificationEnabled": "Aktiviere diese Benachrichtigung",
     "LabelMonitorUsers": "\u00dcberwache Aktivit\u00e4t von:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Heruntergeladene Inhalte die \u00e4lter als dieser Wert sind werden gel\u00f6scht. Sie werden aber weiterhin \u00fcber das Internetstreaming verf\u00fcgbar sein.",
     "ChannelSettingsFormHelp": "Installiere Kan\u00e4le wie beispielsweise \"Trailers\" oder \"Vimeo\" aus dem Plugin Katalog.",
     "ButtonOptions": "Optionen",
+    "ViewTypePlaylists": "Wiedergabelisten",
     "ViewTypeMovies": "Filme",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Spiele",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box R\u00fcckseite",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Men\u00fc",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen f\u00fcr {0}",
     "LabelRunningTimeValue": "Laufzeit: {0}",
     "LabelIpAddressValue": "IP Adresse: {0}",
+    "UserLockedOutWithName": "Benutzer {0} wurde ausgeschlossen",
     "UserConfigurationUpdatedWithName": "Benutzereinstellungen wurden aktualisiert f\u00fcr {0}",
     "UserCreatedWithName": "Benutzer {0} wurde erstellt",
     "UserPasswordChangedWithName": "Das Passwort f\u00fcr Benutzer {0} wurde ge\u00e4ndert",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Falls du fortfahren m\u00f6chtest, gibt bitte das Ergebnis aus folgender Rechnung an:",
     "ButtonIdentify": "Identifizieren",
     "LabelAlbumArtist": "Album-Interpret:",
+    "LabelAlbumArtists": "Alben Interpreten:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community Bewertung:",
     "LabelVoteCount": "Stimmen:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Aufgaben",
     "TabSyncJobs": "Synchronisations-Aufgaben",
     "LabelTagFilterMode": "Modus:",
-    "LabelTagFilterAllowModeHelp": "Wenn erlaubte Tags als Teil einer unter verzweigten Ordnerstruktur verwendet werden, m\u00fcssen \u00fcbergeordnete Verzeichnisse ebenso mit Tags versehen werden."
+    "LabelTagFilterAllowModeHelp": "Wenn erlaubte Tags als Teil einer unter verzweigten Ordnerstruktur verwendet werden, m\u00fcssen \u00fcbergeordnete Verzeichnisse ebenso mit Tags versehen werden.",
+    "HeaderThisUserIsCurrentlyDisabled": "Dieser Benutzer ist aktuell deaktiviert",
+    "MessageReenableUser": "F\u00fcr Reaktivierung schauen Sie unten",
+    "LabelEnableInternetMetadataForTvPrograms": "Lade Internet Metadaten f\u00fcr:",
+    "OptionTVMovies": "TV Filme",
+    "HeaderUpcomingMovies": "Bevorstehende Filme",
+    "HeaderUpcomingPrograms": "Bevorstehende Programme",
+    "ButtonMoreItems": "Mehr...",
+    "LabelShowLibraryTileNames": "Zeige Bibliothek Kachelnamen.",
+    "LabelShowLibraryTileNamesHelp": "Legen Sie fest, ob Beschriftungen unter den Kacheln der Startseite angezeigt werden sollen."
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/el.json b/MediaBrowser.Server.Implementations/Localization/Server/el.json
index 4e16d146a5..2206afbc4b 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/el.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "\u03b5\u03bd\u03c4\u03ac\u03be\u03b5\u03b9",
     "ButtonCancel": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 ",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u0391\u03bd\u03b1\u03c4\u03c1\u03b5\u03be\u03c4\u03b5 \u03c3\u03c4\u03bf media  \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 wiki",
     "LabelCountry": "T\u03b7 \u03c7\u03ce\u03c1\u03b1",
     "LabelLanguage": "\u03a4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "\u03a0\u03c1\u03bf\u03c4\u03b9\u03bc\u03ce\u03bc\u03b5\u03bd\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03bc\u03b5\u03c4\u03b1",
     "LabelSaveLocalMetadata": "\u0391\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03ad\u03c1\u03b3\u03bf \u03c4\u03ad\u03c7\u03bd\u03b7\u03c2 \u03ba\u03b1\u03b9 \u03c4\u03b1 \u03bc\u03b5\u03c4\u03b1\u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03b1 \u03c3\u03b5 \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5\u03c2 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
index a2879f2b5b..457a8bcc94 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organise",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
index 3b532deaea..575bbdc87f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es.json b/MediaBrowser.Server.Implementations/Localization/Server/es.json
index 3f45a6de3f..6974eea8d0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "OK",
     "ButtonCancel": "Cancelar",
+    "ButtonExit": "Exit",
     "ButtonNew": "Nuevo",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Consultar el wiki de la biblioteca de medios",
     "LabelCountry": "Pa\u00eds:",
     "LabelLanguage": "Idioma:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Idioma preferido para metadata",
     "LabelSaveLocalMetadata": "Guardar im\u00e1genes y metadata en las carpetas de medios",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "Mis Plugins",
     "TabCatalog": "Cat\u00e1logo",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Actualizaciones autom\u00e1ticas",
     "HeaderNowPlaying": "Reproduciendo ahora",
     "HeaderLatestAlbums": "\u00dcltimos Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Tv en vivo",
     "LabelNumberOfGuideDays": "N\u00famero de d\u00edas de descarga de la gu\u00eda.",
     "LabelNumberOfGuideDaysHelp": "Descargar m\u00e1s d\u00edas de la gu\u00eda ofrece la posibilidad de programar grabaciones con mayor antelaci\u00f3n y ver m\u00e1s listas, pero tambi\u00e9n tarda m\u00e1s en descargarse. Auto elegir\u00e1 en funci\u00f3n del n\u00famero de canales.",
-    "LabelActiveService": "Activar servicio",
-    "LabelActiveServiceHelp": "Es posible instalar m\u00faltiples plugins de tv, pero s\u00f3lo puede estar activo uno a la vez.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "El servicio de TV en vivo es necesario para poder continuar.",
     "LiveTvPluginRequiredHelp": "Instale uno de los plugins disponibles, como Next Pvr o ServerVmc.",
     "LabelCustomizeOptionsPerMediaType": "Personalizar por tipo de medio:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Nuevo contenido a\u00f1adido",
     "NotificationOptionNewLibraryContentMultiple": "Nuevo contenido a\u00f1adido (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "Por defecto, las notificaciones aparecer\u00e1n en el panel de control. Compruebe el cat\u00e1logo de plugins para instalar opciones adicionales para las notificaciones.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Se requiere el reinicio del servidor",
     "LabelNotificationEnabled": "Activar esta notificaci\u00f3n",
     "LabelMonitorUsers": "Supervisar la actividad de:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Todo contenido descargado anterior se borrar\u00e1. Continuar\u00e1 estando disponible v\u00eda streaming de internet.",
     "ChannelSettingsFormHelp": "Instale canales como Trailers y Vimeo desde el cat\u00e1logo de plugins.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Pel\u00edculas",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Juegos",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
index 7b0e7064e4..e3ddf51ab0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "Si esta ejecutando el servidor desde la fuente, especifique la ruta de acceso a la carpeta dashboard-ui. Todos los archivos de cliente web ser\u00e1n atendidos desde esta ruta.",
     "ButtonConvertMedia": "Convertir Medios",
     "ButtonOrganize": "Organizar",
+    "LinkedToMediaBrowserConnect": "Enlazado con Media Browser Connect",
+    "HeaderSupporterBenefits": "Beneficios del Aficionado",
+    "HeaderAddUser": "Agregar Usuario",
+    "LabelAddConnectSupporterHelp": "Para agregar un usuario que no se encuentra listado, deber\u00e1 primero ligar su cuenta de Media Browser Connect desde su p\u00e1gina de perf\u00edl del usuario.",
+    "LabelPinCode": "C\u00f3digo pin:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancelar",
+    "ButtonExit": "Salir",
     "ButtonNew": "Nuevo",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Rutas",
     "CategorySync": "Sinc.",
+    "TabPlaylist": "Lista de Reproducci\u00f3n",
     "HeaderEasyPinCode": "C\u00f3digo Pin Sencillo",
+    "HeaderGrownupsOnly": "\u00a1Solo Adultos!",
+    "DividerOr": "--o--",
+    "HeaderInstalledServices": "Servicios Instalados",
+    "HeaderAvailableServices": "Servicios Disponibles",
+    "MessageNoServicesInstalled": "No hay servicios instalados en este momento.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "Para acceder, por favor introduzca su c\u00f3digo pin sencillo",
+    "KidsModeAdultInstruction": "Haga clic en el icono de candado en la esquina inferior derecha para configurar o abandonar el modo para ni\u00f1os.",
+    "ButtonConfigurePinCode": "Configurar c\u00f3digo pin",
+    "HeaderAdultsReadHere": "\u00a1Adultos Leer Esto!",
     "RegisterWithPayPal": "Registrar con PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sinc requiere de una Membres\u00eda de Aficionado",
     "HeaderEnjoyDayTrial": "Disfrute de una Prueba Gratuita por 14 D\u00edas",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "Al habilitarlo, los archivos con extensiones .rar y .zip ser\u00e1n detectados como archivos de medios.",
     "LabelEnterConnectUserName": "Nombre de usuario o correo:",
     "LabelEnterConnectUserNameHelp": "Este es el nombre de usuario de su cuenta en l\u00ednea de Media Browser o su contrase\u00f1a.",
+    "LabelEnableEnhancedMovies": "Habilitar visualizaci\u00f3n mejorada de pel\u00edculas",
+    "LabelEnableEnhancedMoviesHelp": "Cuando se activa, la pel\u00edculas ser\u00e1n mostradas como carpetas para incluir trailers, extras, elenco y equipo, y otros contenidos relacionados.",
     "HeaderSyncJobInfo": "Trabajo de Sinc",
     "FolderTypeMixed": "Contenido mezclado",
     "FolderTypeMovies": "Pel\u00edculas",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Consultar la wiki de la biblioteca de medios.",
     "LabelCountry": "Pa\u00eds:",
     "LabelLanguage": "Idioma:",
+    "LabelTimeLimitHours": "L\u00edmite de Tiempo (horas):",
     "ButtonJoinTheDevelopmentTeam": "Unirse al Equipo de Desarrollo.",
     "HeaderPreferredMetadataLanguage": "Idioma preferido para metadatos:",
     "LabelSaveLocalMetadata": "Guardar im\u00e1genes y metadatos en las carpetas de medios",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Tareas Programadas",
     "TabMyPlugins": "Mis Complementos",
     "TabCatalog": "Cat\u00e1logo",
-    "PluginsTitle": "Complementos",
+    "TitlePlugins": "Complementos",
     "HeaderAutomaticUpdates": "Actualizaciones Autom\u00e1ticas",
     "HeaderNowPlaying": "Reproduciendo Ahora",
     "HeaderLatestAlbums": "\u00c1lbums Recientes",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "TV en Vivo",
     "LabelNumberOfGuideDays": "N\u00famero de d\u00edas de datos de la programaci\u00f3n a descargar",
     "LabelNumberOfGuideDaysHelp": "Descargar m\u00e1s d\u00edas de datos de programaci\u00f3n permite programar con mayor anticipaci\u00f3n y ver m\u00e1s listados, pero tomar\u00e1 m\u00e1s tiempo en descargar. Auto har\u00e1 la selecci\u00f3n basada en el n\u00famero de canales.",
-    "LabelActiveService": "Servicio Activo:",
-    "LabelActiveServiceHelp": "Es posible instalar m\u00faltiples complementos de TV, pero solo uno puede estar activo en un momento dado.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Servicios",
     "LiveTvPluginRequired": "Se requiere de un complemento proveedor de servicios de TV en vivo para continuar.",
     "LiveTvPluginRequiredHelp": "Por favor instale alguno de los complementos disponibles, como Next PVR o ServerWMC.",
     "LabelCustomizeOptionsPerMediaType": "Personalizar por tipo de medio:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Nuevo contenido agregado",
     "NotificationOptionNewLibraryContentMultiple": "Nuevo contenido agregado (varios)",
     "NotificationOptionCameraImageUploaded": "Imagen de la c\u00e1mara subida",
-    "SendNotificationHelp": "Por defecto, las notificaciones son enviadas a la bandeja de entrada del panel de control. Navegue el cat\u00e1logo de  complementos para instalar opciones de notificaci\u00f3n adicionales.",
+    "NotificationOptionUserLockedOut": "Usuario bloqueado",
+    "HeaderSendNotificationHelp": "Por defecto, las notificaciones son enviadas a su bandeja de entrada del panel de control. Navegue el cat\u00e1logo de  complementos para instalar opciones de notificaci\u00f3n adicionales.",
     "NotificationOptionServerRestartRequired": "Reinicio del servidor requerido",
     "LabelNotificationEnabled": "Habilitar esta notificaci\u00f3n",
     "LabelMonitorUsers": "Monitorear actividad desde:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "El contenido descargado anterior a esto ser\u00e1 eliminado. Permanecer\u00e1 reproducible via transmisi\u00f3n en tiempo real por Internet.",
     "ChannelSettingsFormHelp": "Instale canales tales como Avances y Vimeo desde el cat\u00e1logo de complementos.",
     "ButtonOptions": "Opciones",
+    "ViewTypePlaylists": "Listas de Reproducci\u00f3n",
     "ViewTypeMovies": "Pel\u00edculas",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Juegos",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Caja",
     "OptionBoxRear": "Reverso de caja",
     "OptionDisc": "Disco",
+    "OptionIcon": "Icono",
     "OptionLogo": "Logotipo",
     "OptionMenu": "Men\u00fa",
     "OptionScreenshot": "Captura de pantalla",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Fall\u00f3 la descarga de subt\u00edtulos para {0}",
     "LabelRunningTimeValue": "Duraci\u00f3n: {0}",
     "LabelIpAddressValue": "Direcci\u00f3n IP: {0}",
+    "UserLockedOutWithName": "El usuario {0} ha sido bloqueado",
     "UserConfigurationUpdatedWithName": "Se ha actualizado la configuraci\u00f3n del usuario {0}",
     "UserCreatedWithName": "Se ha creado el usuario {0}",
     "UserPasswordChangedWithName": "Se ha cambiado la contrase\u00f1a para el usuario {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Si desea continuar, por favor confirme ingresando el valor de:",
     "ButtonIdentify": "Identificar",
     "LabelAlbumArtist": "Artista del \u00e1lbum:",
+    "LabelAlbumArtists": "Artistas del \u00e1lbum:",
     "LabelAlbum": "\u00c1lbum",
     "LabelCommunityRating": "Calificaci\u00f3n de la comunidad:",
     "LabelVoteCount": "Cantidad de votos:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Trabajos",
     "TabSyncJobs": "Trabajos de Sinc",
     "LabelTagFilterMode": "Modo:",
-    "LabelTagFilterAllowModeHelp": "Si las etiquetas permitidas son usadas como parte de una estrucutra compleja de carpetas anidadas, el contenido etiquetado requerir\u00e1 que las carpetas padre sean etiquetadas tambi\u00e9n."
+    "LabelTagFilterAllowModeHelp": "Si las etiquetas permitidas son usadas como parte de una estrucutra compleja de carpetas anidadas, el contenido etiquetado requerir\u00e1 que las carpetas padre sean etiquetadas tambi\u00e9n.",
+    "HeaderThisUserIsCurrentlyDisabled": "Este usuario se encuentra actualmente deshabilitado",
+    "MessageReenableUser": "Vea abajo para volverlo a habilitar",
+    "LabelEnableInternetMetadataForTvPrograms": "Descargar metadatos de Internet para:",
+    "OptionTVMovies": "Pel\u00edculas de TV",
+    "HeaderUpcomingMovies": "Pr\u00f3ximas Pel\u00edculas",
+    "HeaderUpcomingPrograms": "Pr\u00f3ximos Programas",
+    "ButtonMoreItems": "M\u00e1s...",
+    "LabelShowLibraryTileNames": "Mostrar nombres de t\u00edtulo de las bibliotecas",
+    "LabelShowLibraryTileNamesHelp": "Determina si se desplegar\u00e1n etiquetas debajo de los t\u00edtulos de las bibliotecas con la p\u00e1gina principal"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fi.json b/MediaBrowser.Server.Implementations/Localization/Server/fi.json
index d7c79067dd..d549012108 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fi.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Lopeta",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Viittus media kirjaston wikiin.",
     "LabelCountry": "Maa:",
     "LabelLanguage": "Kieli:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Ensisijainen kieli:",
     "LabelSaveLocalMetadata": "Tallenna kuvamateriaali ja metadata media kansioihin.",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fr.json b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
index 29af0bb4d2..abc55ce9a0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "Si vous ex\u00e9cutez le serveur \u00e0 partir des sources, veuillez sp\u00e9cifier le chemin du r\u00e9pertoire dashboard-ui. Tous les fichiers du client web seront servis \u00e0 partir de cet endroit.",
     "ButtonConvertMedia": "Convertir le m\u00e9dia",
     "ButtonOrganize": "Organiser",
+    "LinkedToMediaBrowserConnect": "Connect\u00e9 \u00e0 Media Browser Connect",
+    "HeaderSupporterBenefits": "Avantages de supporteur",
+    "HeaderAddUser": "Ajouter un utilisateur",
+    "LabelAddConnectSupporterHelp": "Pour ajouter un utilisateur non list\u00e9, vous devez d'abord lier son compte \u00e0 Media Browser Connect depuis sa page de profil.",
+    "LabelPinCode": "Code PIN:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Annuler",
+    "ButtonExit": "Sortie",
     "ButtonNew": "Nouveau",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Vid\u00e9o",
     "HeaderPaths": "Chemins",
     "CategorySync": "Sync",
+    "TabPlaylist": "Liste de lecture",
     "HeaderEasyPinCode": "Code Easy Pin",
+    "HeaderGrownupsOnly": "R\u00e9serv\u00e9 aux adultes !",
+    "DividerOr": "-- ou --",
+    "HeaderInstalledServices": "Services install\u00e9s",
+    "HeaderAvailableServices": "Services disponibles",
+    "MessageNoServicesInstalled": "Aucun service n'est actuellement install\u00e9.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "Veuillez entrez votre code Easy PIN :",
+    "KidsModeAdultInstruction": "Cliquez sur l'ic\u00f4ne en forme de cadenas en bas \u00e0 droite pour configurer ou quitter le mode Enfants. Votre code PIN sera requis.",
+    "ButtonConfigurePinCode": "Configurer le code PIN",
+    "HeaderAdultsReadHere": "Section r\u00e9serv\u00e9e aux adultes!",
     "RegisterWithPayPal": "S'enregistrer avec PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync n\u00e9cessite un abonnement actif comme supporteur",
     "HeaderEnjoyDayTrial": "Profitez d'une p\u00e9riode d'essai de 14 jours",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "Activez cette option pour reconna\u00eetre les fichiers portant l'extension .rar ou .zip comme des fichiers de m\u00e9dias. ",
     "LabelEnterConnectUserName": "Nom d'utilisateur ou adresse email :",
     "LabelEnterConnectUserNameHelp": "Ceci est le nom d'utilisateur ou mot de passe de votre compte en ligne Media Browser.",
+    "LabelEnableEnhancedMovies": "Activer le mode d'affichage \u00e9tendu des films",
+    "LabelEnableEnhancedMoviesHelp": "Lorsque ce mode est activ\u00e9, les films seront affich\u00e9s comme des dossiers et incluront les bandes-annonces, les extras, l'\u00e9quipe de tournage et les autre contenus li\u00e9s.",
     "HeaderSyncJobInfo": "T\u00e2che de synchronisation",
     "FolderTypeMixed": "Contenus m\u00e9lang\u00e9s",
     "FolderTypeMovies": "Films",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Se r\u00e9f\u00e9rer au wiki des biblioth\u00e8ques de m\u00e9dia",
     "LabelCountry": "Pays:",
     "LabelLanguage": "Langue:",
+    "LabelTimeLimitHours": "Limite de temps (heures) :",
     "ButtonJoinTheDevelopmentTeam": "Joignez-vous \u00e0 l'\u00e9quipe de d\u00e9veloppement",
     "HeaderPreferredMetadataLanguage": "Langue pr\u00e9f\u00e9r\u00e9e pour les m\u00e9tadonn\u00e9es:",
     "LabelSaveLocalMetadata": "Enregistrer les images et m\u00e9tadonn\u00e9es dans les r\u00e9pertoires de m\u00e9dia",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "T\u00e2ches planifi\u00e9es",
     "TabMyPlugins": "Mes plugins",
     "TabCatalog": "Catalogue",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Mises \u00e0 jour automatiques",
     "HeaderNowPlaying": "Lecture en cours",
     "HeaderLatestAlbums": "Derniers albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "TV en direct",
     "LabelNumberOfGuideDays": "Nombre de jours de donn\u00e9es du guide \u00e0 t\u00e9l\u00e9charger:",
     "LabelNumberOfGuideDaysHelp": "Le t\u00e9l\u00e9chargement de plus de journ\u00e9es dans le guide horaire permet de programmer des enregistrements plus longtemps \u00e0 l'avance et de visualiser plus de contenus, mais prendra \u00e9galement plus de temps. \"Auto\" permettra une s\u00e9lection automatique bas\u00e9e sur le nombre de cha\u00eenes.",
-    "LabelActiveService": "Service Actif:",
-    "LabelActiveServiceHelp": "Plusieurs Plugins de TV peuvent \u00eatre install\u00e9s mais seulement un \u00e0 la fois peut \u00eatre actif.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "Un fournisseur de service de TV en direct est requis pour continuer.",
     "LiveTvPluginRequiredHelp": "Merci d'installer un de nos plugins disponibles, comme Next Pvr ou ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Personnaliser pour le type de m\u00e9dia:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Nouveau contenu ajout\u00e9",
     "NotificationOptionNewLibraryContentMultiple": "Nouveau contenu ajout\u00e9 (multiple)",
     "NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a \u00e9t\u00e9 upload\u00e9e",
-    "SendNotificationHelp": "Par d\u00e9faut, les notifications sont d\u00e9livr\u00e9es dans la bo\u00eete de r\u00e9ception du tableau de bord. Consultez le catalogue de plugins pour installer des options de notifications suppl\u00e9mentaires.",
+    "NotificationOptionUserLockedOut": "Utilisateur verrouill\u00e9",
+    "HeaderSendNotificationHelp": "Par d\u00e9faut, les notifications sont pr\u00e9sent\u00e9es dans la bo\u00eete de messagerie de votre tableau de bord. Parcourrez le catalogue de plugins pour installer des options suppl\u00e9mentaires de notification.",
     "NotificationOptionServerRestartRequired": "Un red\u00e9marrage du serveur est requis",
     "LabelNotificationEnabled": "Activer cette notification",
     "LabelMonitorUsers": "Surveiller les activit\u00e9s de:",
@@ -822,7 +841,7 @@
     "LabelOpenSubtitlesUsername": "Nom d'utilisateur Open Subtitles:",
     "LabelOpenSubtitlesPassword": "Mot de passe Open Subtitles:",
     "HeaderChapterDownloadingHelp": "Lorsque Media Browser scanne vos fichiers vid\u00e9o, il peut facilement t\u00e9l\u00e9charger les noms de chapitre depuis Internet en utilisant le plugin de chapitre tel que ChapterDb.",
-    "LabelPlayDefaultAudioTrack": "Utiliser la flux audio par d\u00e9faut peu importe la langue",
+    "LabelPlayDefaultAudioTrack": "Utiliser le flux audio par d\u00e9faut quelque soit la langue",
     "LabelSubtitlePlaybackMode": "Mode de sous-titres:",
     "LabelDownloadLanguages": "T\u00e9l\u00e9chargement de langues:",
     "ButtonRegister": "S'enregistrer",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Le contenu t\u00e9l\u00e9charg\u00e9 plus vieux que cette valeur sera supprim\u00e9. Il restera disponible \u00e0 la lecture par streaming Internet.",
     "ChannelSettingsFormHelp": "Installer des cha\u00eenes comme \"Trailers\" et \"Vimeo\" dans le catalogue des plugins.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Listes de lecture",
     "ViewTypeMovies": "Films",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Jeux",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Bo\u00eetier",
     "OptionBoxRear": "Dos de bo\u00eetier",
     "OptionDisc": "Disque",
+    "OptionIcon": "Ic\u00f4ne",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Le t\u00e9l\u00e9chargement des sous-titres pour {0} a \u00e9chou\u00e9.",
     "LabelRunningTimeValue": "Dur\u00e9e: {0}",
     "LabelIpAddressValue": "Adresse IP: {0}",
+    "UserLockedOutWithName": "L'utilisateur {0} a \u00e9t\u00e9 verrouill\u00e9",
     "UserConfigurationUpdatedWithName": "La configuration utilisateur de {0} a \u00e9t\u00e9 mise \u00e0 jour",
     "UserCreatedWithName": "L'utilisateur {0} a \u00e9t\u00e9 cr\u00e9\u00e9.",
     "UserPasswordChangedWithName": "Le mot de passe pour l'utilisateur {0} a \u00e9t\u00e9 modifi\u00e9.",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Si vous souhaitez continuer, veuillez confirmer en entrant la valeur de :",
     "ButtonIdentify": "Identifier",
     "LabelAlbumArtist": "Album de l'artiste",
+    "LabelAlbumArtists": "Artistes de l'album :",
     "LabelAlbum": "Album :",
     "LabelCommunityRating": "Note de la communaut\u00e9",
     "LabelVoteCount": "Nombre de votes",
@@ -1353,5 +1376,14 @@
     "TabJobs": "T\u00e2ches",
     "TabSyncJobs": "T\u00e2ches de synchronisation",
     "LabelTagFilterMode": "Mode :",
-    "LabelTagFilterAllowModeHelp": "Si l'autorisation par tags est appliqu\u00e9e \u00e0 un contenu d'un sous-r\u00e9pertoire, les r\u00e9pertoires parents devront \u00e9galement \u00eatre marqu\u00e9s avec ces m\u00eames tags."
+    "LabelTagFilterAllowModeHelp": "Si l'autorisation par tags est appliqu\u00e9e \u00e0 un contenu d'un sous-r\u00e9pertoire, les r\u00e9pertoires parents devront \u00e9galement \u00eatre marqu\u00e9s avec ces m\u00eames tags.",
+    "HeaderThisUserIsCurrentlyDisabled": "Cet utilisateur est actuellement d\u00e9sactiv\u00e9",
+    "MessageReenableUser": "Voir ci-dessous pour le r\u00e9activer",
+    "LabelEnableInternetMetadataForTvPrograms": "T\u00e9l\u00e9charger les m\u00e9ta-donn\u00e9es depuis Internet pour :",
+    "OptionTVMovies": "T\u00e9l\u00e9films",
+    "HeaderUpcomingMovies": "Films \u00e0 venir",
+    "HeaderUpcomingPrograms": "Programmes \u00e0 venir",
+    "ButtonMoreItems": "Plus...",
+    "LabelShowLibraryTileNames": "Voir les noms des affiches de la biblioth\u00e8que",
+    "LabelShowLibraryTileNamesHelp": "D\u00e9termine si les noms doivent \u00eatre affich\u00e9s en dessous des affiches de la biblioth\u00e8que sur la page d'accueil"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/he.json b/MediaBrowser.Server.Implementations/Localization/Server/he.json
index 81e704dda5..4531f517be 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/he.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "\u05d0\u05e9\u05e8",
     "ButtonCancel": "\u05d1\u05d8\u05dc",
+    "ButtonExit": "Exit",
     "ButtonNew": "\u05d7\u05d3\u05e9",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u05e4\u05e0\u05d4 \u05dc\u05de\u05d9\u05d3\u05e2 \u05d0\u05d5\u05d3\u05d5\u05ea \u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4.",
     "LabelCountry": "\u05de\u05d3\u05d9\u05e0\u05d4:",
     "LabelLanguage": "\u05e9\u05e4\u05d4:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "\u05e9\u05e4\u05ea \u05de\u05d9\u05d3\u05e2 \u05de\u05d5\u05e2\u05d3\u05e4\u05ea:",
     "LabelSaveLocalMetadata": "\u05e9\u05de\u05d5\u05e8 \u05ea\u05de\u05d5\u05e0\u05d5\u05ea \u05e8\u05e7\u05e2 \u05d5\u05de\u05d9\u05d3\u05e2 \u05d1\u05ea\u05d5\u05da \u05e1\u05e4\u05e8\u05d9\u05d5\u05ea \u05d4\u05de\u05d3\u05d9\u05d4",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "\u05de\u05e9\u05d9\u05de\u05d5\u05ea \u05de\u05ea\u05d5\u05d6\u05de\u05e0\u05d5\u05ea",
     "TabMyPlugins": "\u05d4\u05ea\u05d5\u05e1\u05e4\u05d9\u05dd \u05e9\u05dc\u05d9",
     "TabCatalog": "\u05e7\u05d8\u05dc\u05d5\u05d2",
-    "PluginsTitle": "\u05ea\u05d5\u05e1\u05e4\u05d9\u05dd",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "\u05e2\u05d9\u05d3\u05db\u05d5\u05e0\u05d9\u05dd \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9\u05dd",
     "HeaderNowPlaying": "\u05de\u05e0\u05d2\u05df \u05e2\u05db\u05e9\u05d9\u05d5",
     "HeaderLatestAlbums": "\u05d0\u05dc\u05d1\u05d5\u05de\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u05d8\u05dc\u05d5\u05d5\u05d9\u05d6\u05d9\u05d4 \u05d7\u05d9\u05d9\u05d4",
     "LabelNumberOfGuideDays": "\u05de\u05e1\u05e4\u05e8 \u05d9\u05de\u05d9 \u05dc\u05d5\u05d7 \u05e9\u05d9\u05d3\u05d5\u05e8\u05d9\u05dd \u05dc\u05d4\u05d5\u05e8\u05d3\u05d4",
     "LabelNumberOfGuideDaysHelp": "\u05d4\u05d5\u05e8\u05d3\u05ea \u05d9\u05d5\u05ea\u05e8 \u05d9\u05de\u05d9 \u05dc\u05d5\u05d7 \u05e9\u05d9\u05d3\u05d5\u05e8\u05d9\u05dd \u05de\u05d0\u05e4\u05e9\u05e8\u05ea \u05d9\u05db\u05d5\u05dc\u05ea \u05dc\u05ea\u05db\u05e0\u05df \u05d5\u05dc\u05e8\u05d0\u05d5\u05ea \u05d9\u05d5\u05ea\u05e8 \u05ea\u05d5\u05db\u05e0\u05d9\u05d5\u05ea \u05e7\u05d3\u05d9\u05de\u05d4, \u05d0\u05d1\u05dc \u05d2\u05dd \u05d6\u05de\u05df \u05d4\u05d4\u05d5\u05e8\u05d3\u05d4 \u05d9\u05e2\u05dc\u05d4. \u05de\u05e6\u05d1 \u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9 \u05d9\u05d9\u05e7\u05d1\u05e2 \u05dc\u05e4\u05e0\u05d9 \u05de\u05e1\u05e4\u05e8 \u05d4\u05e2\u05e8\u05d5\u05e6\u05d9\u05dd.",
-    "LabelActiveService": "\u05e9\u05d9\u05e8\u05d5\u05ea \u05e4\u05e2\u05d9\u05dc:",
-    "LabelActiveServiceHelp": "\u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05e7\u05d9\u05df \u05de\u05e1\u05e4\u05e8 \u05ea\u05d5\u05e1\u05e4\u05d9 \u05d8\u05dc\u05d5\u05d5\u05d9\u05d6\u05d9\u05d4, \u05d0\u05da \u05e8\u05e7 \u05d0\u05d7\u05d3 \u05d9\u05db\u05d5\u05dc \u05dc\u05d4\u05d9\u05d5\u05ea \u05de\u05d5\u05e4\u05e2\u05dc \u05d1\u05db\u05dc \u05e8\u05d2\u05e2 \u05e0\u05ea\u05d5\u05df.",
     "OptionAutomatic": "\u05d0\u05d5\u05d8\u05d5\u05de\u05d8\u05d9",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "\u05d9\u05e9 \u05e6\u05d5\u05e8\u05da \u05d1\u05ea\u05d5\u05e1\u05e3 \u05e1\u05e4\u05e7 \u05d8\u05dc\u05d5\u05d5\u05d9\u05d6\u05d9\u05d4 \u05d7\u05d9\u05d9\u05d4 \u05e2\u05dc \u05de\u05e0\u05ea \u05dc\u05d4\u05de\u05e9\u05d9\u05da.",
     "LiveTvPluginRequiredHelp": "\u05d0\u05e0\u05d0 \u05d4\u05ea\u05e7\u05df \u05d0\u05ea \u05d0\u05d7\u05d3 \u05de\u05d4\u05ea\u05d5\u05e1\u05e4\u05d9\u05dd \u05d4\u05d0\u05e4\u05e9\u05e8\u05d9\u05d9\u05dd \u05e9\u05dc\u05e0\u05d5\u05ea \u05db\u05de\u05d5 Next Pvr \u05d0\u05d5 ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "\u05ea\u05d5\u05db\u05df \u05d7\u05d3\u05e9 \u05e0\u05d5\u05e1\u05e3",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "\u05d1\u05e8\u05d9\u05e8\u05ea \u05d4\u05de\u05d7\u05d3\u05dc \u05d4\u05d9\u05d0 \u05e9\u05d4\u05ea\u05e8\u05d0\u05d5\u05ea \u05de\u05d2\u05d9\u05e2\u05d5\u05ea \u05dc\u05ea\u05d9\u05d1\u05ea \u05d4\u05d3\u05d5\u05d0\u05e8 \u05d4\u05e0\u05db\u05e0\u05e1 \u05e9\u05dc \u05dc\u05d5\u05d7 \u05d4\u05d1\u05e7\u05e8\u05d4. \u05e2\u05d9\u05d9\u05df \u05d1\u05e7\u05d8\u05dc\u05d5\u05d2 \u05d4\u05ea\u05d5\u05e1\u05e4\u05d9\u05dd \u05db\u05d3\u05d9 \u05dc\u05d4\u05ea\u05e7\u05d9\u05df \u05d0\u05e4\u05e9\u05e8\u05d5\u05d9\u05d5\u05ea \u05e0\u05d5\u05e1\u05e4\u05d5\u05ea \u05dc\u05e7\u05d1\u05dc\u05ea \u05d4\u05ea\u05e8\u05d0\u05d5\u05ea",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "\u05e0\u05d3\u05e8\u05e9\u05ea \u05d4\u05e4\u05e2\u05dc\u05d4 \u05de\u05d7\u05d3\u05e9 \u05e9\u05dc \u05d4\u05e9\u05e8\u05ea",
     "LabelNotificationEnabled": "\u05d0\u05e4\u05e9\u05e8 \u05d4\u05ea\u05e8\u05d0\u05d4 \u05d6\u05d5",
     "LabelMonitorUsers": "\u05e2\u05e7\u05d5\u05d1 \u05d0\u05d7\u05e8 \u05e4\u05e2\u05d9\u05dc\u05d5\u05ea \u05de:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/hr.json b/MediaBrowser.Server.Implementations/Localization/Server/hr.json
index 4258eb5f18..e1fb685492 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/hr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/hr.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Odustani",
+    "ButtonExit": "Exit",
     "ButtonNew": "Novo",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Informirajte se o medijskoj bibilioteci wiki",
     "LabelCountry": "Zemlja:",
     "LabelLanguage": "Jezik:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "\u017deljeni metadata jezik:",
     "LabelSaveLocalMetadata": "Snimi ilustracije i metadata u medijske mape",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Raspored zadataka",
     "TabMyPlugins": "Moji dodaci",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Dodaci",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatske nadogradnje",
     "HeaderNowPlaying": "Sad se izvodi",
     "HeaderLatestAlbums": "Zadnji albumi",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "TV",
     "LabelNumberOfGuideDays": "Broj dana TV vodi\u010da za preuzet:",
     "LabelNumberOfGuideDaysHelp": "Preuzimanje vi\u0161e dana TV vodi\u010da, omogu\u0107iti \u0107e vam zakazivanje snimanja dalje u budu\u0107nost , ali \u0107e i preuzimanje du\u017ee trajati. Automaski - odabir \u0107e se prilagoditi broju kanala.",
-    "LabelActiveService": "Aktivne usluge:",
-    "LabelActiveServiceHelp": "Vi\u0161e TV dodataka mo\u017ee biti instalirano ali samo jedan mo\u017ee biti aktivan u isto vrijeme.",
     "OptionAutomatic": "Automatski",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "TV u\u017eivo usluga je obavezna ako \u017eelite nastaviti.",
     "LiveTvPluginRequiredHelp": "Molimo instalirajte jedan od dostupnih dodataka, kaoo \u0161to su Next Pvr ili ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Novi sadr\u017eaj dodan",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "Zadano je da se sve obavijesti dostave na upravlja\u010dku plo\u010du. Pretra\u017eite katalog dodataka kako bi instalirali dodatne opcije obavijesti.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Potrebno ponovo pokretanje servera",
     "LabelNotificationEnabled": "Omogu\u0107i ovu obavijest",
     "LabelMonitorUsers": "Obrazac nadzora aktivnosti:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/it.json b/MediaBrowser.Server.Implementations/Localization/Server/it.json
index 2f1c1812b3..63bf3d8f44 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/it.json
@@ -43,20 +43,36 @@
     "HeaderDeveloperOptions": "Opzioni Sviluppatore",
     "OptionEnableWebClientResponseCache": "Abilita la cache del client web",
     "OptionDisableForDevelopmentHelp": "Configura questi parametri per sviluppatori  del client web",
-    "OptionEnableWebClientResourceMinification": "Enable web client resource minification",
+    "OptionEnableWebClientResourceMinification": "Abilita la minimizzazione delle risorse del client web",
     "LabelDashboardSourcePath": "Percorso sorgente client web",
     "LabelDashboardSourcePathHelp": "se si sta eseguendo il server da una sorgente, specifica il percorso dell'interfaccia. Tutti i file per i client saranno presi da questo percorso",
     "ButtonConvertMedia": "Converti media",
     "ButtonOrganize": "Organizza",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Codice Pin",
     "ButtonOk": "OK",
     "ButtonCancel": "Annulla",
+    "ButtonExit": "Esci",
     "ButtonNew": "Nuovo",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Percorsi",
     "CategorySync": "Sinc.zza",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Codice pin",
+    "HeaderGrownupsOnly": "Solo adulti",
+    "DividerOr": "- o -",
+    "HeaderInstalledServices": "Servizi installati",
+    "HeaderAvailableServices": "Servizi disponibili",
+    "MessageNoServicesInstalled": "Nessun servizio attualmente installato",
+    "HeaderToAccessPleaseEnterEasyPinCode": "Per accedere per favore inserisci il tuo codice pin",
+    "KidsModeAdultInstruction": "Clicca sull'icona del lucchetto nell'angolo in basso a destra per configurare o abbandonare la modalit\u00e0 bambini. Verr\u00e0 richiesto il tuo codice pin",
+    "ButtonConfigurePinCode": "Configura codice pin",
+    "HeaderAdultsReadHere": "Adulti leggete qui!",
     "RegisterWithPayPal": "Registra con PayPal",
     "HeaderSyncRequiresSupporterMembership": "La sincronizzazione richiede un'iscrizione come supporter",
     "HeaderEnjoyDayTrial": "Goditi la tua prova gratuita di 14 giorni",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "se attivato, i file con estensione .rar e .zip saranno considerati come file multimediali.",
     "LabelEnterConnectUserName": "Nome Utente o email:",
     "LabelEnterConnectUserNameHelp": "Questo \u00e8 il tuo nome utente, o password, per il tuo account online di Media Browser.",
+    "LabelEnableEnhancedMovies": "Abilita le visuali film migliorate",
+    "LabelEnableEnhancedMoviesHelp": "Quando abilitato, i film verranno mostrati come cartelle che includono i trailer, gli extra, il cast & crew, e altri contenuti correlati.",
     "HeaderSyncJobInfo": "Attiv. di Sinc.",
     "FolderTypeMixed": "contenuto misto",
     "FolderTypeMovies": "Film",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Fare riferimento alla wiki libreria multimediale.",
     "LabelCountry": "Nazione:",
     "LabelLanguage": "Lingua:",
+    "LabelTimeLimitHours": "Tempo limite (ore):",
     "ButtonJoinTheDevelopmentTeam": "Unisciti al Team di Sviluppo",
     "HeaderPreferredMetadataLanguage": "Lingua dei metadati preferita:",
     "LabelSaveLocalMetadata": "Salva immagini e metadati nelle cartelle multimediali",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Operazioni Pianificate",
     "TabMyPlugins": "Plugins Installati",
     "TabCatalog": "Catalogo",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Aggiornamenti Automatici",
     "HeaderNowPlaying": "In Riproduzione",
     "HeaderLatestAlbums": "Ultimi Album",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Tv in diretta",
     "LabelNumberOfGuideDays": "Numero di giorni per i quali scaricare i dati della guida:",
     "LabelNumberOfGuideDaysHelp": "Scaricando pi\u00f9 giorni si avr\u00e0 la possibilit\u00e0 di pianificare in anticipo pi\u00f9 programmi e vedere pi\u00f9 liste. 'Auto': MB sceglier\u00e0 automaticamente in base al numero di canali.",
-    "LabelActiveService": "Servizio attivo:",
-    "LabelActiveServiceHelp": "Possono essere installati pi\u00f9 plugins Tv ma solo uno alla volta pu\u00f2 essere attivato",
     "OptionAutomatic": "Automatico",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "E' richiesto il servizio LIVE TV per continuare.",
     "LiveTvPluginRequiredHelp": "Installa un servizio disponibile, come Next Pvr or ServerWMC.",
     "LabelCustomizeOptionsPerMediaType": "Personalizza per il tipo di supporto:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto",
     "NotificationOptionNewLibraryContentMultiple": "Nuovi contenuti aggiunti",
     "NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata",
-    "SendNotificationHelp": "Per impostazione predefinita, le notifiche vengono inviate alla casella della pagina principale. Sfoglia il catalogo plugin da installare opzioni di notifica aggiuntive.",
+    "NotificationOptionUserLockedOut": "Utente bloccato",
+    "HeaderSendNotificationHelp": "Per impostazione predefinita, le notifiche vengono inviate alla casella della pagina principale. Sfoglia il catalogo plugin da installare opzioni di notifica aggiuntive.",
     "NotificationOptionServerRestartRequired": "Riavvio del server necessario",
     "LabelNotificationEnabled": "Abilita questa notifica",
     "LabelMonitorUsers": "Monitorare l'attivit\u00e0 da:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Contenuti scaricati pi\u00f9 vecchi di questo limite sarnno cancellati. Rimarranno riproducibili via internet in streaming.",
     "ChannelSettingsFormHelp": "Installare canali come Trailer e Vimeo nel catalogo plugin.",
     "ButtonOptions": "Opzioni",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Film",
     "ViewTypeTvShows": "Serie Tv",
     "ViewTypeGames": "Giochi",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disco",
+    "OptionIcon": "Icona",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Immagine",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Sottotitoli non scaricati per {0}",
     "LabelRunningTimeValue": "Durata: {0}",
     "LabelIpAddressValue": "Indirizzo IP: {0}",
+    "UserLockedOutWithName": "L'utente {0} \u00e8 stato bloccato",
     "UserConfigurationUpdatedWithName": "Configurazione utente \u00e8 stata aggiornata per {0}",
     "UserCreatedWithName": "Utente {0} \u00e8 stato creato",
     "UserPasswordChangedWithName": "Password utente cambiata per {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Se si desidera continuare, si prega di confermare inserendo il valore di:",
     "ButtonIdentify": "Identifica",
     "LabelAlbumArtist": "Artista Album",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Voto Comunit\u00e0:",
     "LabelVoteCount": "Totale Voti:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Attivit\u00e0",
     "TabSyncJobs": "Attiv. di Sinc.",
     "LabelTagFilterMode": "Modalit\u00e0:",
-    "LabelTagFilterAllowModeHelp": "Se i tag permessi vengono utilizzati come parte di una struttura di cartelle profondamente nidificate, il contenuto che viene etichettato richieder\u00e0 cartelle principali di essere etichettato come bene."
+    "LabelTagFilterAllowModeHelp": "Se i tag permessi vengono utilizzati come parte di una struttura di cartelle profondamente nidificate, il contenuto che viene etichettato richieder\u00e0 cartelle principali di essere etichettato come bene.",
+    "HeaderThisUserIsCurrentlyDisabled": "Questo utente \u00e8 al momento disabilitato",
+    "MessageReenableUser": "Guarda in basso per ri-abilitare",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "Pi\u00f9...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/kk.json b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
index e74c0ea840..c0a7bcbd12 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
@@ -48,18 +48,34 @@
     "LabelDashboardSourcePathHelp": "\u0415\u0433\u0435\u0440 \u0441\u0435\u0440\u0432\u0435\u0440 \u049b\u0430\u0439\u043d\u0430\u0440 \u043a\u043e\u0434\u044b\u043d\u0430\u043d \u0436\u04b1\u043c\u044b\u0441 \u0456\u0441\u0442\u0435\u0441\u0435, dashboard-ui \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d\u0430 \u0436\u043e\u043b\u0434\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437. \u0412\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0456\u04a3 \u0431\u0430\u0440\u043b\u044b\u049b \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b \u043e\u0441\u044b \u0436\u0430\u0439\u0493\u0430\u0441\u044b\u043c\u0434\u0430\u043d \u0448\u044b\u0493\u0430\u0440\u044b\u043b\u0430\u0434\u044b.",
     "ButtonConvertMedia": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0443",
     "ButtonOrganize": "\u04b0\u0439\u044b\u043c\u0434\u0430\u0441\u0442\u044b\u0440\u0443",
+    "LinkedToMediaBrowserConnect": "Media Browser Connect \u04af\u0448\u0456\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u049b\u0430\u043d",
+    "HeaderSupporterBenefits": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u0430\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b\u0442\u0430\u0440\u044b",
+    "HeaderAddUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u04af\u0441\u0442\u0435\u0443",
+    "LabelAddConnectSupporterHelp": "\u0422\u0456\u0437\u0456\u043c\u0434\u0435 \u0436\u043e\u049b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u04af\u0441\u0442\u0435\u0443 \u04af\u0448\u0456\u043d, \u0430\u043b\u0434\u044b\u043c\u0435\u043d \u043e\u043d\u044b\u04a3 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u044b\u049b \u043f\u0440\u043e\u0444\u0430\u0439\u043b \u0431\u0435\u0442\u0456\u043d\u0435\u043d Media Browser Connect \u04af\u0448\u0456\u043d \u043e\u043d\u044b\u04a3 \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u0441\u0456\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443\u044b\u04a3\u044b\u0437 \u049b\u0430\u0436\u0435\u0442.",
+    "LabelPinCode": "PIN-\u043a\u043e\u0434:",
     "ButtonOk": "\u0416\u0430\u0440\u0430\u0439\u0434\u044b",
     "ButtonCancel": "\u0411\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
+    "ButtonExit": "\u0428\u044b\u0493\u0443",
     "ButtonNew": "\u0416\u0430\u0441\u0430\u0443",
     "HeaderTV": "\u0422\u0414",
     "HeaderAudio": "\u0414\u044b\u0431\u044b\u0441",
     "HeaderVideo": "\u0411\u0435\u0439\u043d\u0435",
     "HeaderPaths": "\u0416\u043e\u043b\u0434\u0430\u0440",
     "CategorySync": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443",
+    "TabPlaylist": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456",
     "HeaderEasyPinCode": "\u041e\u04a3\u0430\u0439\u0442\u044b\u043b\u0493\u0430\u043d PIN-\u043a\u043e\u0434",
+    "HeaderGrownupsOnly": "\u0422\u0435\u043a \u0435\u0440\u0435\u0441\u0435\u043a\u0442\u0435\u0440!",
+    "DividerOr": "-- \u043d\u0435\u043c\u0435\u0441\u0435 --",
+    "HeaderInstalledServices": "\u041e\u0440\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440",
+    "HeaderAvailableServices": "\u049a\u0430\u0442\u044b\u043d\u0430\u0443\u043b\u044b \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440",
+    "MessageNoServicesInstalled": "\u049a\u0430\u0437\u0456\u0440\u0433\u0456 \u0443\u0430\u049b\u044b\u0442\u0442\u0430 \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u043c\u0430\u0493\u0430\u043d",
+    "HeaderToAccessPleaseEnterEasyPinCode": "\u049a\u0430\u0442\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u043e\u04a3\u0430\u0439\u0442\u044b\u043b\u0493\u0430\u043d PIN-\u043a\u043e\u0434\u0442\u044b \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437",
+    "KidsModeAdultInstruction": "\u0422\u0435\u04a3\u0448\u0435\u0443 \u04af\u0448\u0456\u043d \u0442\u04e9\u043c\u0435\u0434\u0435\u0433\u0456 \u043e\u04a3 \u0436\u0430\u049b\u0442\u0430\u0493\u044b \u049b\u04b1\u043b\u044b\u043f \u0431\u0435\u043b\u0433\u0456\u0448\u0435\u0441\u0456\u043d \u043d\u04b1\u049b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0431\u0430\u043b\u0430\u043b\u044b\u049b \u0440\u0435\u0436\u0456\u043c\u0456\u043d \u049b\u0430\u043b\u0434\u044b\u0440\u044b\u04a3\u044b\u0437. PIN-\u043a\u043e\u0434\u044b\u04a3\u044b\u0437 \u049b\u0430\u0436\u0435\u0442 \u0431\u043e\u043b\u0430\u0434\u044b.",
+    "ButtonConfigurePinCode": "PIN-\u043a\u043e\u0434\u0442\u044b \u0442\u0435\u04a3\u0448\u0435\u0443",
+    "HeaderAdultsReadHere": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0435\u0440, \u043c\u044b\u043d\u0430\u043d\u044b \u043e\u049b\u044b\u04a3\u044b\u0437!",
     "RegisterWithPayPal": "PayPal \u0430\u0440\u049b\u044b\u043b\u044b \u0442\u0456\u0440\u043a\u0435\u043b\u0443",
     "HeaderSyncRequiresSupporterMembership": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u043b\u044b\u049b \u043c\u04af\u0448\u0435\u043b\u0456\u043a \u049b\u0430\u0436\u0435\u0442",
-    "HeaderEnjoyDayTrial": "14 \u043a\u04af\u043d \u0442\u0435\u0433\u0456\u043d \u0441\u044b\u043d\u0430\u043f \u043a\u04e9\u0440\u0456\u04a3\u0456\u0437",
+    "HeaderEnjoyDayTrial": "\u0422\u0435\u0433\u0456\u043d \u0441\u044b\u043d\u0430\u0443\u0434\u044b 14 \u043a\u04af\u043d \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u04a3\u044b\u0456\u0437",
     "LabelSyncTempPath": "\u0423\u0430\u049b\u044b\u0442\u0448\u0430 \u0444\u0430\u0439\u043b \u0436\u043e\u043b\u044b:",
     "LabelSyncTempPathHelp": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u04b1\u043c\u044b\u0441 \u049b\u0430\u043b\u0442\u0430\u043d\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437. \u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u043a\u0435\u0437\u0456\u043d\u0434\u0435 \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d \u0442\u04af\u0440\u043b\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0441\u044b \u043e\u0440\u044b\u043d\u0434\u0430 \u0441\u0430\u049b\u0442\u0430\u043b\u0430\u0434\u044b.",
     "LabelCustomCertificatePath": "\u041a\u0443\u04d9\u043b\u0456\u043a \u0436\u043e\u043b\u044b:",
@@ -70,9 +86,11 @@
     "OptionDetectArchiveFilesAsMediaHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, .rar \u0436\u04d9\u043d\u0435 .zip \u043a\u0435\u04a3\u0435\u0439\u0442\u0456\u043c\u0434\u0435\u0440\u0456 \u0431\u0430\u0440 \u0444\u0430\u0439\u043b\u0434\u0430\u0440 \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0442\u0430\u0431\u044b\u043b\u0430\u0434\u044b.",
     "LabelEnterConnectUserName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u044b \u043d\u0435\u043c\u0435\u0441\u0435 \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0456",
     "LabelEnterConnectUserNameHelp": "\u0411\u04b1\u043b - \u0441\u0456\u0437\u0434\u0456\u04a3 Media Browser \u0436\u0435\u043b\u0456\u043b\u0456\u043a \u0442\u0456\u0440\u043a\u0435\u043b\u0433\u0456\u04a3\u0456\u0437\u0434\u0456\u04a3 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u044b \u043d\u0435\u043c\u0435\u0441\u0435 \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0456.",
+    "LabelEnableEnhancedMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440\u0434\u0456\u04a3 \u0436\u0430\u049b\u0441\u0430\u0440\u0442\u044b\u043b\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043d \u049b\u043e\u0441\u0443",
+    "LabelEnableEnhancedMoviesHelp": "\u049a\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u0434\u0430, \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043b\u0435\u0440\u0434\u0456, \u049b\u043e\u0441\u044b\u043c\u0448\u0430\u043b\u0430\u0440\u0434\u044b, \u0442\u04af\u0441\u0456\u0440\u0443\u0433\u0435 \u049b\u0430\u0442\u044b\u0441\u049b\u0430\u043d\u0434\u0430\u0440\u0434\u044b \u0436\u04d9\u043d\u0435 \u0431\u0430\u0441\u049b\u0430 \u049b\u0430\u0442\u044b\u0441\u0442\u044b \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u049b\u0430\u043c\u0442\u0443 \u04af\u0448\u0456\u043d, \u0444\u0438\u043b\u044c\u043c\u0434\u0435\u0440 \u049b\u0430\u043b\u0442\u0430 \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456",
     "HeaderSyncJobInfo": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u044b",
     "FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 \u043c\u0430\u0437\u043c\u04b1\u043d",
-    "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
+    "FolderTypeMovies": "\u041a\u0438\u043d\u043e",
     "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
     "FolderTypeAdultVideos": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0456\u043a \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440",
     "FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u0442\u0443\u0440\u0430\u043b\u044b \u0443\u0438\u043a\u0438 \u0456\u0448\u0456\u043d\u0435\u043d \u049b\u0430\u0440\u0430\u04a3\u044b\u0437.",
     "LabelCountry": "\u0415\u043b:",
     "LabelLanguage": "\u0422\u0456\u043b:",
+    "LabelTimeLimitHours": "\u0423\u0430\u049b\u044b\u0442 \u0448\u0435\u0433\u0456 (\u0441\u0430\u0493\u0430\u0442):",
     "ButtonJoinTheDevelopmentTeam": "\u0416\u0430\u0441\u0430\u049b\u0442\u0430\u0443\u0448\u044b\u043b\u0430\u0440 \u0442\u043e\u0431\u044b\u043d\u0430 \u043a\u0456\u0440\u0443",
     "HeaderPreferredMetadataLanguage": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u0456\u043b\u0456\u043d\u0456\u04a3 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456:",
     "LabelSaveLocalMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u0430\u0441\u044b\u0493\u044b\u0448 \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u044b \u0456\u0448\u0456\u043d\u0434\u0435 \u0441\u0430\u049b\u0442\u0430\u0443",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "\u0416\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0443\u0448\u044b",
     "TabMyPlugins": "\u041c\u0435\u043d\u0456\u04a3 \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440\u0456\u043c",
     "TabCatalog": "\u0422\u0456\u0437\u0456\u043c\u0434\u0435\u043c\u0435",
-    "PluginsTitle": "\u041f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440",
+    "TitlePlugins": "\u041f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440",
     "HeaderAutomaticUpdates": "\u0410\u0432\u0442\u043e\u0436\u0430\u04a3\u0430\u0440\u0442\u0443\u043b\u0430\u0440",
     "HeaderNowPlaying": "\u049a\u0430\u0437\u0456\u0440 \u043e\u0439\u043d\u0430\u0442\u044b\u043b\u0443\u0434\u0430",
     "HeaderLatestAlbums": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u04a3\u0433\u0456 \u0430\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u042d\u0444\u0438\u0440\u043b\u0456\u043a \u0422\u0414",
     "LabelNumberOfGuideDays": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u04af\u0448\u0456\u043d \u0410\u043d\u044b\u049b\u0442\u0430\u0493\u044b\u0448 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043d\u0434\u0435\u0433\u0456 \u043a\u04af\u043d \u0441\u0430\u043d\u044b:",
     "LabelNumberOfGuideDaysHelp": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a \u043a\u04af\u043d\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443 \u0410\u043d\u044b\u049b\u0442\u0430\u0493\u044b\u0448 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043d\u0456\u04a3 \u049b\u04b1\u043d\u0434\u044b\u043b\u044b\u0493\u044b\u043d \u043a\u04e9\u0442\u0435\u0440\u0435\u0434\u0456 \u0434\u0435 \u0430\u043b\u0434\u044b\u043d-\u0430\u043b\u0430 \u0436\u043e\u0441\u043f\u0430\u0440\u043b\u0430\u0443 \u04af\u0448\u0456\u043d \u049b\u0430\u0431\u0456\u043b\u0435\u0442\u0456\u043d \u0436\u04d9\u043d\u0435 \u043a\u04e9\u0431\u0456\u0440\u0435\u043a \u0442\u0456\u0437\u0431\u0435\u043b\u0435\u0440 \u043a\u04e9\u0440\u0443\u0434\u0456 \u049b\u0430\u043c\u0442\u0430\u043c\u0430\u0441\u044b\u0437 \u0435\u0442\u0435\u0434\u0456, \u0431\u0456\u0440\u0430\u049b \u0431\u04b1\u043b \u0436\u04af\u043a\u0442\u0435\u0443 \u0443\u0430\u049b\u044b\u0442\u044b\u043d \u0434\u0430 \u0441\u043e\u0437\u0434\u044b\u0440\u0430\u0434\u044b. \u0410\u0432\u0442\u043e\u0442\u0430\u04a3\u0434\u0430\u0443 \u0430\u0440\u043d\u0430 \u0441\u0430\u043d\u044b\u043d\u0430 \u043d\u0435\u0433\u0456\u0437\u0434\u0435\u043b\u0456\u043d\u0435\u0434\u0456.",
-    "LabelActiveService": "\u0411\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u049b\u044b\u0437\u043c\u0435\u0442:",
-    "LabelActiveServiceHelp": "\u0411\u0456\u0440\u043d\u0435\u0448\u0435 \u0422\u0414 \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440 \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d, \u0431\u0456\u0440\u0430\u049b \u0441\u043e\u043b \u043a\u0435\u0437\u0434\u0435 \u0442\u0435\u043a \u049b\u0430\u043d\u0430 \u0431\u0456\u0440\u0435\u0443\u0456 \u0431\u0435\u043b\u0441\u0435\u043d\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
     "OptionAutomatic": "\u0410\u0432\u0442\u043e\u0442\u0430\u04a3\u0434\u0430\u0443",
+    "HeaderServices": "\u049a\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440",
     "LiveTvPluginRequired": "\u0416\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443 \u04af\u0448\u0456\u043d \u044d\u0444\u0438\u0440\u043b\u0456\u043a \u0422\u0414 \u049b\u044b\u0437\u043c\u0435\u0442\u0456\u043d \u0436\u0435\u0442\u043a\u0456\u0437\u0443\u0448\u0456\u0441\u0456 \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0456 \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.",
     "LiveTvPluginRequiredHelp": "\u0411\u0456\u0437\u0434\u0456\u04a3 \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 (Next Pvr \u043d\u0435 ServerWmc \u0441\u0438\u044f\u049b\u0442\u044b) \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440\u0434\u0456\u04a3 \u0431\u0456\u0440\u0435\u0443\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.",
     "LabelCustomizeOptionsPerMediaType": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448 \u0442\u04af\u0440\u0456 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u0443:",
@@ -627,7 +645,7 @@
     "LabelSupporterKey": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456 (\u042d-\u043f\u043e\u0448\u0442\u0430\u0434\u0430\u043d \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u04a3\u0456\u0437)",
     "LabelSupporterKeyHelp": "\u049a\u0430\u0443\u044b\u043c\u0434\u0430\u0441\u0442\u044b\u049b Media Browser \u0430\u0440\u043d\u0430\u043f \u0436\u0430\u0441\u0430\u049b\u0442\u0430\u0493\u0430\u043d \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u0430\u0440\u0442\u044b\u049b\u0448\u044b\u043b\u044b\u049b\u0442\u0430\u0440\u0434\u044b \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u0443\u044b\u043d \u0431\u0430\u0441\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456\u043d \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437.",
     "MessageInvalidKey": "\u0416\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456 \u0436\u043e\u049b \u043d\u0435\u043c\u0435\u0441\u0435 \u0434\u04b1\u0440\u044b\u0441 \u0435\u043c\u0435\u0441",
-    "ErrorMessageInvalidKey": "\u049a\u0430\u0439 \u0435\u0440\u0435\u043a\u0448\u0435 \u043c\u0430\u0437\u043c\u04b1\u043d \u0431\u043e\u043b\u0441\u0430 \u0436\u0430\u0437\u044b\u043b\u0443 \u04af\u0448\u0456\u043d, \u0441\u0456\u0437 \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b Media Browser \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b\u0441\u044b \u0431\u043e\u043b\u0443\u044b\u04a3\u044b\u0437 \u049b\u0430\u0436\u0435\u0442. \u04d8\u0437\u0456\u0440\u043b\u0435\u0443\u0456 \u0436\u0430\u043b\u0493\u0430\u0441\u0443\u0434\u0430\u0493\u044b \u043d\u0435\u0433\u0456\u0437\u0433\u0456 \u04e9\u043d\u0456\u043c \u04af\u0448\u0456\u043d \u04af\u043b\u0435\u0441 \u049b\u043e\u0441\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u0436\u0430\u049b\u0442\u0430\u04a3\u044b\u0437.",
+    "ErrorMessageInvalidKey": "\u049a\u0430\u0439 \u0441\u044b\u0439\u0430\u049b\u044b\u043b\u044b\u049b \u043c\u0430\u0437\u043c\u04b1\u043d \u0431\u043e\u043b\u0441\u0430 \u0436\u0430\u0437\u044b\u043b\u0443 \u04af\u0448\u0456\u043d, \u0441\u0456\u0437 \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b Media Browser \u0436\u0430\u049b\u0442\u0430\u0443\u0448\u044b\u0441\u044b \u0431\u043e\u043b\u0443\u044b\u04a3\u044b\u0437 \u049b\u0430\u0436\u0435\u0442. \u04d8\u0437\u0456\u0440\u043b\u0435\u0443\u0456 \u0436\u0430\u043b\u0493\u0430\u0441\u0443\u0434\u0430\u0493\u044b \u043d\u0435\u0433\u0456\u0437\u0433\u0456 \u04e9\u043d\u0456\u043c \u04af\u0448\u0456\u043d \u04af\u043b\u0435\u0441 \u049b\u043e\u0441\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u0436\u0430\u049b\u0442\u0430\u04a3\u044b\u0437.",
     "HeaderDisplaySettings": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0456",
     "TabPlayTo": "\u049a\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430 \u043e\u0439\u043d\u0430\u0442\u0443",
     "LabelEnableDlnaServer": "DLNA \u0441\u0435\u0440\u0432\u0435\u0440\u0456\u043d \u049b\u043e\u0441\u0443",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u04af\u0441\u0442\u0435\u043b\u0433\u0435\u043d",
     "NotificationOptionNewLibraryContentMultiple": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u049b\u043e\u0441\u044b\u043b\u0434\u044b (\u043a\u04e9\u043f\u0442\u0435\u0433\u0435\u043d)",
     "NotificationOptionCameraImageUploaded": "\u041a\u0430\u043c\u0435\u0440\u0430\u0434\u0430\u043d \u0444\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442 \u0436\u04af\u043a\u0442\u0435\u043b\u0433\u0435\u043d",
-    "SendNotificationHelp": "\u0425\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443\u043b\u0430\u0440 \u0431\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u0441\u044b\u043d\u0434\u0430\u0493\u044b \u04d9\u0434\u0435\u043f\u043a\u0456 \u043a\u0456\u0440\u0456\u0441 \u0436\u04d9\u0448\u0456\u0433\u0456\u043d\u0435 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u043b\u0435\u0434\u0456. \u049a\u043e\u0441\u044b\u043c\u0448\u0430 \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443 \u049b\u04b1\u0440\u0430\u043b\u0434\u0430\u0440\u044b\u043d \u043e\u0440\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u043c\u0435\u0441\u0456\u043d \u0448\u043e\u043b\u044b\u04a3\u044b\u0437.",
+    "NotificationOptionUserLockedOut": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u049b\u04b1\u0440\u0441\u0430\u0443\u043b\u044b",
+    "HeaderSendNotificationHelp": "\u04d8\u0434\u0435\u043f\u043a\u0456\u0434\u0435, \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443\u043b\u0430\u0440 \u0431\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u04a3\u044b\u0437\u0434\u0430\u0493\u044b \u043a\u0456\u0440\u0456\u0441 \u0436\u04d9\u0448\u0456\u0433\u0456\u043d\u0435 \u0436\u0435\u0442\u043a\u0456\u0437\u0456\u043b\u0435\u0434\u0456. \u049a\u043e\u0441\u044b\u043c\u0448\u0430 \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443 \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u043a\u0442\u0435\u0440\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u043c\u0435\u0441\u0456\u043d \u0448\u043e\u043b\u044b\u04a3\u044b\u0437.",
     "NotificationOptionServerRestartRequired": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456 \u049b\u0430\u0439\u0442\u0430 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443 \u049b\u0430\u0436\u0435\u0442",
     "LabelNotificationEnabled": "\u0411\u04b1\u043b \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u043c\u0430\u043d\u044b \u049b\u043e\u0441\u0443",
     "LabelMonitorUsers": "\u041c\u044b\u043d\u0430\u043d\u044b\u04a3 \u04d9\u0440\u0435\u043a\u0435\u0442\u0442\u0435\u0440\u0456\u043d \u0431\u0430\u049b\u044b\u043b\u0430\u0443:",
@@ -677,7 +696,7 @@
     "CategorySystem": "\u0416\u04af\u0439\u0435",
     "CategoryApplication": "\u049a\u043e\u043b\u0434\u0430\u043d\u0431\u0430",
     "CategoryPlugin": "\u041f\u043b\u0430\u0433\u0438\u043d",
-    "LabelMessageTitle": "\u0425\u0430\u0431\u0430\u0440 \u043c\u04d9\u0442\u0456\u043d\u0456:",
+    "LabelMessageTitle": "\u0425\u0430\u0431\u0430\u0440 \u0442\u0430\u049b\u044b\u0440\u044b\u0431\u044b:",
     "LabelAvailableTokens": "\u049a\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0442\u0430\u04a3\u0431\u0430\u043b\u0430\u0443\u044b\u0448\u0442\u0430\u0440:",
     "AdditionalNotificationServices": "\u049a\u043e\u0441\u044b\u043c\u0448\u0430 \u0445\u0430\u0431\u0430\u0440\u043b\u0430\u043d\u0434\u044b\u0440\u0443 \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043f\u043b\u0430\u0433\u0438\u043d\u0434\u0435\u0440 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u043c\u0435\u0441\u0456\u043d \u0448\u043e\u043b\u044b\u04a3\u044b\u0437.",
     "OptionAllUsers": "\u0411\u0430\u0440\u043b\u044b\u049b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440",
@@ -885,12 +904,12 @@
     "OptionCommunityMostWatchedSort": "\u0415\u04a3 \u043a\u04e9\u043f \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u0434\u0430\u0440",
     "TabNextUp": "\u041a\u0435\u0437\u0435\u043a\u0442\u0456",
     "HeaderBecomeMediaBrowserSupporter": "Media Browser \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u044b \u0431\u043e\u043b\u044b\u04a3\u044b\u0437",
-    "TextEnjoyBonusFeatures": "\u0421\u044b\u0439\u0430\u049b\u044b \u0435\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a\u0442\u0435\u0440\u043c\u0435\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437",
+    "TextEnjoyBonusFeatures": "\u0421\u044b\u0439\u0430\u049b\u044b \u0435\u0440\u0435\u043a\u0448\u0435\u043b\u0456\u043a\u0442\u0435\u0440\u0434\u0456 \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437",
     "MessageNoMovieSuggestionsAvailable": "\u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0444\u0438\u043b\u044c\u043c \u04b1\u0441\u044b\u043d\u044b\u0441\u0442\u0430\u0440\u044b \u0430\u0493\u044b\u043c\u0434\u0430 \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0435\u043c\u0435\u0441. \u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440\u0434\u0456 \u049b\u0430\u0440\u0430\u0443\u0434\u044b \u0436\u04d9\u043d\u0435 \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u0434\u044b \u0431\u0430\u0441\u0442\u0430\u04a3\u044b\u0437, \u0441\u043e\u043d\u0434\u0430 \u0430\u0440\u043d\u0430\u043b\u0493\u0430\u043d \u04b1\u0441\u044b\u043d\u044b\u0442\u0430\u0440\u044b\u04a3\u044b\u0437\u0434\u044b \u043a\u04e9\u0440\u0443 \u04af\u0448\u0456\u043d \u049b\u0430\u0439\u0442\u0430 \u043a\u0435\u043b\u0456\u04a3\u0456\u0437.",
     "MessageNoCollectionsAvailable": "\u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440 \u0441\u0456\u0437\u0433\u0435 \u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440\u0434\u0456\u04a3, \u0422\u0435\u043b\u0435\u0445\u0438\u043a\u0430\u044f\u043b\u0430\u0440\u0434\u044b\u04a3, \u0410\u043b\u044c\u0431\u043e\u043c\u0434\u0430\u0440\u0434\u044b\u04a3, \u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440\u0434\u044b\u04a3, \u0436\u04d9\u043d\u0435 \u041e\u0439\u044b\u043d\u0434\u0430\u0440\u0434\u044b\u04a3 \u0434\u0435\u0440\u0431\u0435\u0441\u0442\u0435\u043d\u0434\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0442\u043e\u043f\u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043c\u0435\u043d \u0442\u0430\u043c\u0430\u0448\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u0416\u0438\u044b\u043d\u0442\u044b\u049b\u0442\u0430\u0440 \u0436\u0430\u0441\u0430\u0443\u044b\u043d \u0431\u0430\u0441\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \"+\" \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u0433\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437.",
     "MessageNoPlaylistsAvailable": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0456 \u0431\u0456\u0440 \u043a\u0435\u0437\u0434\u0435 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043c\u0430\u0437\u043c\u04b1\u043d \u0442\u0456\u0437\u0456\u043c\u0456\u043d \u0436\u0430\u0441\u0430\u0443\u0493\u0430  \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0433\u0435 \u0442\u0430\u0440\u043c\u0430\u049b\u0442\u0430\u0440\u0434\u044b \u04af\u0441\u0442\u0435\u0443 \u04af\u0448\u0456\u043d, \u0442\u0456\u043d\u0442\u0443\u0456\u0440\u0434\u0456\u04a3 \u043e\u04a3 \u0436\u0430\u049b \u0442\u04af\u0439\u043c\u0435\u0448\u0456\u0433\u0456\u043d \u0431\u0430\u0441\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0442\u04af\u0440\u0442\u0456\u043f \u0436\u04d9\u043d\u0435 \u04b1\u0441\u0442\u0430\u043f \u0442\u04b1\u0440\u044b\u04a3\u044b\u0437, \u0441\u043e\u043d\u0434\u0430 \u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0456\u043d\u0435 \u04af\u0441\u0442\u0435\u0443 \u0434\u0435\u0433\u0435\u043d\u0434\u0456 \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437.",
     "MessageNoPlaylistItemsAvailable": "\u041e\u0441\u044b \u043e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c \u0430\u0493\u044b\u043c\u0434\u0430\u0493\u044b \u0443\u0430\u049b\u044b\u0442\u0442\u0430 \u0431\u043e\u0441.",
-    "ButtonDismiss": "\u0416\u0430\u0441\u044b\u0440\u0443",
+    "ButtonDismiss": "\u049a\u0430\u0431\u044b\u043b\u0434\u0430\u043c\u0430\u0443",
     "ButtonEditOtherUserPreferences": "\u041e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b\u04a3 \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u044b\u043d, \u0441\u0443\u0440\u0435\u0442\u0456\u043d \u0436\u04d9\u043d\u0435 \u04e9\u0437\u0456\u043d\u0434\u0456\u043a \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440\u0456\u043d \u04e9\u04a3\u0434\u0435\u0443.",
     "LabelChannelStreamQuality": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u0493\u044b\u043d\u043c\u0435\u043d \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u0443 \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0456:",
     "LabelChannelStreamQualityHelp": "\u0421\u0430\u043f\u0430\u0441\u044b\u043d \u0448\u0435\u043a\u0442\u0435\u0443\u0456 \u0436\u0430\u0442\u044b\u049b\u0442\u0430\u0443 \u0430\u0493\u044b\u043d\u043c\u0435\u043d \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u0443\u044b\u043d\u0430 \u049b\u0430\u043c\u0442\u0430\u043c\u0430\u0441\u044b\u0437 \u0435\u0442\u0443 \u04af\u0448\u0456\u043d, \u04e9\u0442\u043a\u0456\u0437\u0443 \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u0433\u0456 \u0442\u04e9\u043c\u0435\u043d \u043e\u0440\u0442\u0430\u0434\u0430 \u043a\u04e9\u043c\u0435\u043a \u0431\u0435\u0440\u0443 \u043c\u04af\u043c\u043a\u0456\u043d.",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "\u0411\u04b1\u0434\u0430\u043d \u0431\u04b1\u0440\u044b\u043d\u0493\u044b \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0493\u0430\u043d \u043c\u0430\u0437\u043c\u04af\u043d \u0436\u043e\u0439\u044b\u043b\u0430\u0434\u044b. \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0430\u0440\u049b\u044b\u043b\u044b \u0430\u0493\u044b\u043d\u043c\u0435\u043d \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u0443 \u04d9\u0434\u0456\u0441\u0456\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043f \u043e\u0439\u043d\u0430\u0442\u0443 \u0456\u0441\u0442\u0435 \u049b\u0430\u043b\u0430\u0434\u044b.",
     "ChannelSettingsFormHelp": "\u041f\u043b\u0430\u0433\u0438\u043d \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u043c\u0435\u0441\u0456\u043d\u0434\u0435\u0433\u0456 Trailers \u0436\u04d9\u043d\u0435 Vimeo \u0441\u0438\u044f\u049b\u0442\u044b \u0430\u0440\u043d\u0430\u043b\u0430\u0440\u0434\u044b \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.",
     "ButtonOptions": "\u041d\u04b1\u0441\u049b\u0430\u043b\u0430\u0440\u0493\u0430",
+    "ViewTypePlaylists": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0442\u0456\u0437\u0456\u043c\u0434\u0435\u0440\u0456",
     "ViewTypeMovies": "\u041a\u0438\u043d\u043e",
     "ViewTypeTvShows": "\u0422\u0414",
     "ViewTypeGames": "\u041e\u0439\u044b\u043d\u0434\u0430\u0440",
@@ -981,7 +1001,7 @@
     "LabelCache": "\u041a\u044d\u0448:",
     "LabelLogs": "\u0416\u04b1\u0440\u043d\u0430\u043b\u0434\u0430\u0440:",
     "LabelMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440:",
-    "LabelImagesByName": "\u0410\u0442\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440:",
+    "LabelImagesByName": "\u0410\u0442\u0430\u043b\u0493\u0430\u043d \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440:",
     "LabelTranscodingTemporaryFiles": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u044b\u043d\u044b\u04a3 \u0443\u0430\u049b\u044b\u0442\u0448\u0430 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b:",
     "HeaderLatestMusic": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u043c\u0443\u0437\u044b\u043a\u0430",
     "HeaderBranding": "\u0411\u0435\u0437\u0435\u043d\u0434\u0456\u0440\u0443",
@@ -1048,6 +1068,7 @@
     "OptionBox": "\u049a\u043e\u0440\u0430\u043f",
     "OptionBoxRear": "\u049a\u043e\u0440\u0430\u043f \u0430\u0440\u0442\u044b",
     "OptionDisc": "\u0414\u0438\u0441\u043a\u0456",
+    "OptionIcon": "\u0411\u0435\u043b\u0433\u0456\u0448\u0435",
     "OptionLogo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f",
     "OptionMenu": "\u041c\u04d9\u0437\u0456\u0440",
     "OptionScreenshot": "\u042d\u043a\u0440\u0430\u043d \u0441\u0443\u0440\u0435\u0442\u0456",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u043b\u0435\u0440 {0} \u04af\u0448\u0456\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0443\u044b \u0441\u04d9\u0442\u0441\u0456\u0437",
     "LabelRunningTimeValue": "\u0406\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0443 \u0443\u0430\u049b\u044b\u0442\u044b: {0}",
     "LabelIpAddressValue": "IP \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b: {0}",
+    "UserLockedOutWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u049b\u04b1\u0440\u0441\u0430\u0443\u043b\u044b",
     "UserConfigurationUpdatedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0456\u043c \u0436\u0430\u04a3\u0430\u0440\u0442\u044b\u043b\u0434\u044b",
     "UserCreatedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u0436\u0430\u0441\u0430\u043b\u0493\u0430\u043d",
     "UserPasswordChangedWithName": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b {0} \u04af\u0448\u0456\u043d \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437 \u04e9\u0437\u0433\u0435\u0440\u0442\u0456\u043b\u0434\u0456",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "\u0415\u0433\u0435\u0440 \u0436\u0430\u043b\u0430\u0441\u0442\u044b\u0440\u0443\u0434\u044b \u049b\u0430\u043b\u0430\u0441\u0430\u04a3\u044b\u0437, \u043c\u044b\u043d\u0430\u043d\u044b\u04a3 \u043c\u04d9\u043d\u0456\u043d \u0435\u043d\u0433\u0456\u0437\u0456\u043f \u0440\u0430\u0441\u0442\u0430\u04a3\u044b\u0437:",
     "ButtonIdentify": "\u0410\u043d\u044b\u049b\u0442\u0430\u0443",
     "LabelAlbumArtist": "\u0410\u043b\u044c\u0431\u043e\u043c \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u0441\u044b:",
+    "LabelAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u044b:",
     "LabelAlbum": "\u0410\u043b\u044c\u0431\u043e\u043c:",
     "LabelCommunityRating": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b:",
     "LabelVoteCount": "\u0414\u0430\u0443\u044b\u0441 \u0435\u0441\u0435\u0431\u0456:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "\u0416\u04b1\u043c\u044b\u0441\u0442\u0430\u0440",
     "TabSyncJobs": "\u04ae\u043d\u0434\u0435\u0441\u0442\u0456\u0440\u0443 \u0436\u04b1\u043c\u044b\u0441\u0442\u0430\u0440\u044b",
     "LabelTagFilterMode": "\u0420\u0435\u0436\u0456\u043c:",
-    "LabelTagFilterAllowModeHelp": "\u0415\u0433\u0435\u0440 \u04b1\u0439\u0493\u0430\u0440\u044b\u043d\u0434\u044b \u0442\u0435\u0433\u0442\u0435\u0440 \u0442\u0435\u0440\u0435\u04a3 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u049b\u0430\u043b\u0442\u0430 \u049b\u04b1\u0440\u044b\u043b\u044b\u043c\u044b\u043d\u044b\u04a3 \u0431\u04e9\u043b\u0456\u0433\u0456 \u0431\u043e\u043b\u0441\u0430, \u043e\u043d\u0434\u0430 \u0442\u0435\u0433\u0442\u0435\u0440\u043c\u0435\u043d \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u043c\u0430\u0437\u043c\u04b1\u043d\u0493\u0430, \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u0442\u0435\u043a\u0442\u0456\u043a \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0431\u043e\u043b\u0443\u044b \u0442\u0430\u043b\u0430\u043f \u0435\u0442\u0456\u043b\u0435\u0434\u0456."
+    "LabelTagFilterAllowModeHelp": "\u0415\u0433\u0435\u0440 \u04b1\u0439\u0493\u0430\u0440\u044b\u043d\u0434\u044b \u0442\u0435\u0433\u0442\u0435\u0440 \u0442\u0435\u0440\u0435\u04a3 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u049b\u0430\u043b\u0442\u0430 \u049b\u04b1\u0440\u044b\u043b\u044b\u043c\u044b\u043d\u044b\u04a3 \u0431\u04e9\u043b\u0456\u0433\u0456 \u0431\u043e\u043b\u0441\u0430, \u043e\u043d\u0434\u0430 \u0442\u0435\u0433\u0442\u0435\u0440\u043c\u0435\u043d \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u043c\u0430\u0437\u043c\u04b1\u043d\u0493\u0430, \u0441\u043e\u043d\u0434\u0430\u0439-\u0430\u049b \u0431\u0435\u043b\u0433\u0456\u043b\u0435\u043d\u0433\u0435\u043d \u0442\u0435\u043a\u0442\u0456\u043a \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0431\u043e\u043b\u0443\u044b \u0442\u0430\u043b\u0430\u043f \u0435\u0442\u0456\u043b\u0435\u0434\u0456.",
+    "HeaderThisUserIsCurrentlyDisabled": "\u041e\u0441\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u049b\u0430\u0437\u0456\u0440\u0433\u0456 \u043a\u0435\u0437\u0434\u0435 \u0430\u0436\u044b\u0440\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
+    "MessageReenableUser": "\u049a\u0430\u0439\u0442\u0430 \u049b\u043e\u0441\u0443 \u04af\u0448\u0456\u043d \u0442\u04e9\u043c\u0435\u043d\u0434\u0435 \u049b\u0430\u0440\u0430\u04a3\u044b\u0437",
+    "LabelEnableInternetMetadataForTvPrograms": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
+    "OptionTVMovies": "\u0422\u0414-\u0444\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
+    "HeaderUpcomingMovies": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d \u0444\u0438\u043b\u044c\u043c\u0434\u0435\u0440",
+    "HeaderUpcomingPrograms": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d \u0431\u0435\u0440\u043b\u0456\u043c\u0434\u0435\u0440",
+    "ButtonMoreItems": "\u041a\u04e9\u0431\u0456\u0440\u0435\u043a...",
+    "LabelShowLibraryTileNames": "\u0422\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u0442\u0430\u049b\u0442\u0430\u0439\u0448\u0430\u043b\u0430\u0440\u044b\u043d\u044b\u04a3 \u0430\u0442\u0430\u0443\u043b\u0430\u0440\u044b\u043d \u043a\u04e9\u0440\u0441\u0435\u0442\u0443",
+    "LabelShowLibraryTileNamesHelp": "\u0411\u0430\u0441\u0442\u044b \u0431\u0435\u0442\u0442\u0435 \u0442\u0430\u0441\u044b\u0493\u044b\u0448\u0445\u0430\u043d\u0430 \u0442\u0430\u049b\u0442\u0430\u0439\u0448\u0430\u043b\u0430\u0440\u044b \u0430\u0441\u0442\u044b\u043d\u0434\u0430 \u0436\u0430\u0437\u0443\u043b\u0430\u0440  \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u0435 \u043c\u0435 \u0435\u043a\u0435\u043d\u0456 \u0430\u043d\u044b\u049b\u0442\u0430\u043b\u0430\u0434\u044b."
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ko.json b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
index 68b92c66bc..50db34faa5 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ko.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ms.json b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
index 6dd714458f..2b1852e0b5 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nb.json b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
index 0e08ddf21a..35934bd8ed 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
@@ -4,8 +4,8 @@
     "LabelGithub": "Github",
     "LabelSwagger": "Swagger",
     "LabelStandard": "Standard",
-    "LabelApiDocumentation": "Api Dokumentasjon",
-    "LabelDeveloperResources": "Utvikler Ressurser",
+    "LabelApiDocumentation": "API-dokumentasjon",
+    "LabelDeveloperResources": "Ressurser for Utviklere",
     "LabelBrowseLibrary": "Browse biblioteket",
     "LabelConfigureMediaBrowser": "Konfigurer Media Browser",
     "LabelOpenLibraryViewer": "\u00c5pne Biblioteket",
@@ -17,126 +17,145 @@
     "LabelYoureDone": "Ferdig!",
     "WelcomeToMediaBrowser": "Velkommen til Media Browser!",
     "TitleMediaBrowser": "Media Browser",
-    "ThisWizardWillGuideYou": "Denne wizarden vil guide deg gjennom server-konfigurasjonen. For \u00e5 begynne, vennligst velg ditt foretrukne spr\u00e5k.",
+    "ThisWizardWillGuideYou": "Denne wizarden vil guide deg gjennom server-konfigurasjonen. For \u00e5 begynne, vennligst velg spr\u00e5k.",
     "TellUsAboutYourself": "Fortell om deg selv",
-    "ButtonQuickStartGuide": "Hurtig start veiledning",
+    "ButtonQuickStartGuide": "Hurtigstartveiledning",
     "LabelYourFirstName": "Ditt fornavn",
-    "MoreUsersCanBeAddedLater": "Du kan legge til flere brukere senere via Dashboard",
+    "MoreUsersCanBeAddedLater": "Du kan legge til flere brukere senere via Dashbord",
     "UserProfilesIntro": "Media Browser inkluderer innebygd st\u00f8tte for bruker profiler som tilbyr brukere innstillinger for visning, avspillerstatus og begrensning p\u00e5 innhold.",
     "LabelWindowsService": "Windows Service",
     "AWindowsServiceHasBeenInstalled": "Windows Service har blitt installert",
     "WindowsServiceIntro1": "Media Browser Server kj\u00f8rer normalt som en desktop-applikasjon med et tray-ikon, men om du foretrekker at det kj\u00f8res som en bakgrunnsprosess, kan du i stedet starte den fra windows service control panel.",
     "WindowsServiceIntro2": "Hvis du bruker Windows, v\u00e6r oppmerksom p\u00e5 at det ikke kan kj\u00f8res samtidig som ikonet, slik at du trenger \u00e5 g\u00e5 ut av \"trayen\" for \u00e5 kj\u00f8re tjenesten. Tjenesten m\u00e5 ogs\u00e5 konfigureres med administratorrettigheter via kontrollpanelet. V\u00e6r oppmerksom p\u00e5 at p\u00e5 denne tiden tjenesten ikke er i stand til selv-oppdatering, s\u00e5 nye versjoner vil kreve manuell interaksjon.",
-    "WizardCompleted": "Det er alt vi trenger for n\u00e5. Media Browser har begynt \u00e5 samle inn informasjon om ditt media bibliotek. Sjekk ut noen av v\u00e5re apps, og klikk s\u00e5 <b>Ferdig<\/b> for \u00e5 vise <b>Server Dashboard<\/b>.",
+    "WizardCompleted": "Det er alt vi trenger n\u00e5. Media Browser har begynt \u00e5 samle inn informasjon om ditt mediabibliotek. Sjekk ut noen av v\u00e5re apps, og klikk s\u00e5 <b>Ferdig<\/b> for \u00e5 vise <b>Server Dashboard<\/b>.",
     "LabelConfigureSettings": "Konfigurer innstillinger",
-    "LabelEnableVideoImageExtraction": "Aktiver videobildet utvinning",
-    "VideoImageExtractionHelp": "For videoer som ikke allerede har bilder, og at vi ikke klarer \u00e5 finne internettbilder for. Dette vil tilf\u00f8re noen ytterligere tid til den opprinnelige biblioteket s\u00f8king, men vil resultere i en mer tiltalende presentasjon.",
-    "LabelEnableChapterImageExtractionForMovies": "Pakk ut kapittelbilde utvinning for Filmer",
-    "LabelChapterImageExtractionForMoviesHelp": "Extracting chapter images will allow clients to display graphical scene selection menus. The process can be slow, cpu-intensive and may require several gigabytes of space. It runs as a nightly scheduled task, although this is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.",
-    "LabelEnableAutomaticPortMapping": "Sl\u00e5 p\u00e5 automatisk port mapping",
-    "LabelEnableAutomaticPortMappingHelp": "UPnP tillater automatiserte routere konfigurasjoner for enkel ekstern tilgang. Denne funksjonen s\u00f8ttes ikke av alle routere.",
-    "HeaderTermsOfService": "Media Browser Vilk\u00e5r for Service",
-    "MessagePleaseAcceptTermsOfService": "Vennligst aksepter v\u00e5re service vilk\u00e5r og personvern policy f\u00f8r du fortsetter.",
-    "OptionIAcceptTermsOfService": "Jeg aksepterer service vilk\u00e5rene",
-    "ButtonPrivacyPolicy": "Personvern policy",
-    "ButtonTermsOfService": "Service Vilk\u00e5r",
-    "HeaderDeveloperOptions": "Utvikler opsjoner",
-    "OptionEnableWebClientResponseCache": "Aktiver web klient respons caching",
-    "OptionDisableForDevelopmentHelp": "Konfigurer disse ved behov for web klient utvikler form\u00e5l.",
-    "OptionEnableWebClientResourceMinification": "Aktiver web klient ressurs minifisering",
-    "LabelDashboardSourcePath": "Web klient kilde sti:",
-    "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
-    "ButtonConvertMedia": "Convert media",
-    "ButtonOrganize": "Organize",
+    "LabelEnableVideoImageExtraction": "Aktiv\u00e9r uthenting av stillbilder fra video",
+    "VideoImageExtractionHelp": "For videoer som ikke allerede har bilder, og som vi ikke klarer \u00e5 finne internettbilder for. Dette gj\u00f8r at det f\u00f8rste biblioteks\u00f8ket tar noe lenger tid, men vil resultere i en mer tiltalende presentasjon.",
+    "LabelEnableChapterImageExtractionForMovies": "Generer kapittelbilde for Filmer",
+    "LabelChapterImageExtractionForMoviesHelp": "Uthenting av kapittelbilder gj\u00f8r klientene i stand til \u00e5 vise grafiske menyer for valg av scene. Prosessen kan v\u00e6re treg, CPU-intensiv og kan kreve sv\u00e6rt mange gigabytes lagringsplass. Dette kj\u00f8res som en nattlig oppgave, og kan konfigureres under Planlagte Aktiviteter. Det anbefales ikke \u00e5 kj\u00f8re denne jobben n\u00e5r serveren brukes til annet.",
+    "LabelEnableAutomaticPortMapping": "Sl\u00e5 p\u00e5 automatisk port-mapping",
+    "LabelEnableAutomaticPortMappingHelp": "UPnP tillater automatisert router-konfigurasjon for enkel ekstern tilgang. Denne funksjonen st\u00f8ttes ikke av alle routere.",
+    "HeaderTermsOfService": "Media Browser Servicevilk\u00e5r",
+    "MessagePleaseAcceptTermsOfService": "Vennligst aksepter v\u00e5re servicevilk\u00e5r og personvernpolicy f\u00f8r du fortsetter.",
+    "OptionIAcceptTermsOfService": "Jeg aksepterer servicevilk\u00e5rene",
+    "ButtonPrivacyPolicy": "Personvernpolicy",
+    "ButtonTermsOfService": "Servicevilk\u00e5r",
+    "HeaderDeveloperOptions": "Utvikler-innstillinger",
+    "OptionEnableWebClientResponseCache": "Aktiver webklient respons-caching",
+    "OptionDisableForDevelopmentHelp": "Konfigurer disse i forbindelse med utvikling av web-klienten.",
+    "OptionEnableWebClientResourceMinification": "Aktiver ressursminimering for webklient",
+    "LabelDashboardSourcePath": "Webklient kildesti:",
+    "LabelDashboardSourcePathHelp": "Hvis serveren kj\u00f8rer fra kildekode, angi sti til mappe for dashboard-ui. Alle filer for webklienten kommer fra denne mappen.",
+    "ButtonConvertMedia": "Konverter media",
+    "ButtonOrganize": "Organiser",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
-    "ButtonCancel": "avbryt",
+    "ButtonCancel": "Avbryt",
+    "ButtonExit": "Exit",
     "ButtonNew": "Ny",
     "HeaderTV": "TV",
     "HeaderAudio": "Lyd",
     "HeaderVideo": "Video",
     "HeaderPaths": "Stier",
-    "CategorySync": "Sync",
-    "HeaderEasyPinCode": "Easy Pin Code",
-    "RegisterWithPayPal": "Register with PayPal",
-    "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
-    "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
-    "LabelSyncTempPath": "Temporary file path:",
-    "LabelSyncTempPathHelp": "Specify a custom sync working folder. Converted media created during the sync process will be stored here.",
-    "LabelCustomCertificatePath": "Custom certificate path:",
-    "LabelCustomCertificatePathHelp": "Supply your own ssl certificate .pfx file. If omitted, the server will create a self-signed certificate.",
-    "TitleNotifications": "Notifications",
-    "ButtonDonateWithPayPal": "Doner med PayPal",
-    "OptionDetectArchiveFilesAsMedia": "Detect archive files as media",
-    "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
+    "CategorySync": "Synk",
+    "TabPlaylist": "Playlist",
+    "HeaderEasyPinCode": "Enkel PIN-kode",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
+    "RegisterWithPayPal": "Registrer med PayPal",
+    "HeaderSyncRequiresSupporterMembership": "Synkronisering krever st\u00f8ttemedlemskap",
+    "HeaderEnjoyDayTrial": "Hygg deg med en 14-dagers gratis pr\u00f8veperiode",
+    "LabelSyncTempPath": "Midlertidig fil-sti:",
+    "LabelSyncTempPathHelp": "Spesifiser din egen synk-mappe. Konverterte mediefiler opprettet ved synkronisering vil lagres her.",
+    "LabelCustomCertificatePath": "Sti for eget sertifikat:",
+    "LabelCustomCertificatePathHelp": "Angi ditt eget SSL-sertifikats .ptx-fil. Hvis feltet er blankt vil serveren opprette et eget selv-signert sertifikat.",
+    "TitleNotifications": "Beskjeder",
+    "ButtonDonateWithPayPal": "Don\u00e9r med PayPal",
+    "OptionDetectArchiveFilesAsMedia": "Behandle arkivfiler som media",
+    "OptionDetectArchiveFilesAsMediaHelp": "Hvis aktivert blir .rar- og .zipfiler behandlet som mediafiler.",
     "LabelEnterConnectUserName": "Brukernavn eller epost:",
-    "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
-    "HeaderSyncJobInfo": "Sync Job",
-    "FolderTypeMixed": "Mixed content",
+    "LabelEnterConnectUserNameHelp": "Dette er din Media Browser online brukernavn eller passord.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
+    "HeaderSyncJobInfo": "Synk.jobb",
+    "FolderTypeMixed": "Forskjellig innhold",
     "FolderTypeMovies": "Filmer",
     "FolderTypeMusic": "Musikk",
-    "FolderTypeAdultVideos": "Voksen videoer",
+    "FolderTypeAdultVideos": "Voksen-videoer",
     "FolderTypePhotos": "Foto",
-    "FolderTypeMusicVideos": "Musikk videoer",
-    "FolderTypeHomeVideos": "Hjemme videoer",
+    "FolderTypeMusicVideos": "Musikk-videoer",
+    "FolderTypeHomeVideos": "Hjemme-videoer",
     "FolderTypeGames": "Spill",
     "FolderTypeBooks": "B\u00f8ker",
     "FolderTypeTvShows": "TV",
-    "FolderTypeInherit": "Inherit",
-    "LabelContentType": "Content type:",
-    "TitleScheduledTasks": "Scheduled Tasks",
+    "FolderTypeInherit": "Arve",
+    "LabelContentType": "Innholdstype:",
+    "TitleScheduledTasks": "Planlagt oppgaver",
     "HeaderSetupLibrary": "Konfigurer media-biblioteket",
     "ButtonAddMediaFolder": "Legg til media-mappe",
-    "LabelFolderType": "Mappe typpe",
-    "ReferToMediaLibraryWiki": "Se i media-bibliotek wikien",
-    "LabelCountry": "LAnd",
+    "LabelFolderType": "Mappetype",
+    "ReferToMediaLibraryWiki": "Se i wik for media-biblioteket.",
+    "LabelCountry": "Land:",
     "LabelLanguage": "Spr\u00e5k:",
-    "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
+    "LabelTimeLimitHours": "Time limit (hours):",
+    "ButtonJoinTheDevelopmentTeam": "Bli med i utvikler-teamet",
     "HeaderPreferredMetadataLanguage": "Foretrukket spr\u00e5k for metadata",
     "LabelSaveLocalMetadata": "Lagre cover og metadata i medie-mappene",
-    "LabelSaveLocalMetadataHelp": "Lagring av artwork og metadata direkte gjennom media mapper vil legge dem en plass hvor de lett kan editeres.",
+    "LabelSaveLocalMetadataHelp": "Lagring av artwork og metadata direkte gjennom mediemapper vil legge dem et sted hvor de lett kan editeres.",
     "LabelDownloadInternetMetadata": "Last ned cover og metadata fra internett",
-    "LabelDownloadInternetMetadataHelp": "MEdia Browser kan laste ned informasjon om mediet for en rikere presentasjon",
+    "LabelDownloadInternetMetadataHelp": "Media Browser kan laste ned informasjon om mediet for en mer fullstendig presentasjon",
     "TabPreferences": "Preferanser",
     "TabPassword": "Passord",
     "TabLibraryAccess": "Bibliotektilgang",
-    "TabAccess": "Access",
+    "TabAccess": "Tilgang",
     "TabImage": "Bilde",
-    "TabProfile": "profil",
+    "TabProfile": "Profil",
     "TabMetadata": "Metadata",
     "TabImages": "Bilder",
     "TabNotifications": "Varslinger",
     "TabCollectionTitles": "Titler",
-    "HeaderDeviceAccess": "Device Access",
-    "OptionEnableAccessFromAllDevices": "Enable access from all devices",
-    "OptionEnableAccessToAllChannels": "Enable access to all channels",
-    "OptionEnableAccessToAllLibraries": "Enable access to all libraries",
-    "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.",
-    "LabelDisplayMissingEpisodesWithinSeasons": "Vis episoder som sesongen mangler",
+    "HeaderDeviceAccess": "Enhetstilgang",
+    "OptionEnableAccessFromAllDevices": "Gi tilgang fra alle enheter",
+    "OptionEnableAccessToAllChannels": "Gi tilgang til alle kanaler",
+    "OptionEnableAccessToAllLibraries": "Gi tilgang til alle bibliotek",
+    "DeviceAccessHelp": "Dette gjelder bare for enheter som som kan unikt identifiseres og vil ikke forindre tilgang fra nettleser. Filtrering av brukerens enhet vil forhindre dem fra \u00e5 bruke nye enheter inntil de har blitt godkjent her.",
+    "LabelDisplayMissingEpisodesWithinSeasons": "Vis episoder som mangler fra sesongen",
     "LabelUnairedMissingEpisodesWithinSeasons": "Vis episoder som enn\u00e5 ikke har blitt sendt",
     "HeaderVideoPlaybackSettings": "Innstillinger for video-avspilling",
-    "HeaderPlaybackSettings": "Avspillings Innstillinger",
+    "HeaderPlaybackSettings": "Avspillingsinnstillinger",
     "LabelAudioLanguagePreference": "Foretrukket lydspor:",
     "LabelSubtitleLanguagePreference": "Foretrukket undertekst:",
     "OptionDefaultSubtitles": "Standard",
-    "OptionOnlyForcedSubtitles": "Kun tvunget undertekster",
-    "OptionAlwaysPlaySubtitles": "Alltid spill undertekster",
-    "OptionNoSubtitles": "Ingen Undertekster",
-    "OptionDefaultSubtitlesHelp": "Undertekster som samsvarer med foretrukket spr\u00e5k vil bli lastet n\u00e5r lyden er p\u00e5 et fremmed spr\u00e5k.",
-    "OptionOnlyForcedSubtitlesHelp": "Kun undertekster marker som tvunget vil bli lastet.",
-    "OptionAlwaysPlaySubtitlesHelp": "Undertekster som samsvarer med foretrukket spr\u00e5k vil bli lastet uavhengig lydens spr\u00e5k.",
+    "OptionOnlyForcedSubtitles": "Kun tvungede undertekster",
+    "OptionAlwaysPlaySubtitles": "Alltid vis undertekster",
+    "OptionNoSubtitles": "Ingen undertekster",
+    "OptionDefaultSubtitlesHelp": "Undertekster som samsvarer med foretrukket spr\u00e5k vil bli vist n\u00e5r lyden er p\u00e5 et fremmed spr\u00e5k.",
+    "OptionOnlyForcedSubtitlesHelp": "Kun undertekster markert som tvunget vil bli vist.",
+    "OptionAlwaysPlaySubtitlesHelp": "Undertekster som samsvarer med foretrukket spr\u00e5k vil bli vist uavhengig lydens spr\u00e5k.",
     "OptionNoSubtitlesHelp": "Undertekster vil ikke bli lastet som standard.",
     "TabProfiles": "Profiler",
     "TabSecurity": "Sikkerhet",
     "ButtonAddUser": "Ny bruker",
     "ButtonAddLocalUser": "Legg til lokal bruker",
     "ButtonInviteUser": "Invit\u00e9r Bruker",
-    "ButtonSave": "lagre",
-    "ButtonResetPassword": "Resett passord",
-    "LabelNewPassword": "Nytt passord",
-    "LabelNewPasswordConfirm": "Bekreft nytt passord",
+    "ButtonSave": "Lagre",
+    "ButtonResetPassword": "Tilbakestill passord",
+    "LabelNewPassword": "Nytt passord:",
+    "LabelNewPasswordConfirm": "Bekreft nytt passord:",
     "HeaderCreatePassword": "Lag nytt passord",
-    "LabelCurrentPassword": "N\u00e5v\u00e6rende passord",
-    "LabelMaxParentalRating": "Maks tillatt sensur.",
+    "LabelCurrentPassword": "N\u00e5v\u00e6rende passord:",
+    "LabelMaxParentalRating": "Maks tillatt sensur:",
     "MaxParentalRatingHelp": "Innhold med h\u00f8yere aldersgrense vil bli skjult for brukeren",
     "LibraryAccessHelp": "Velg media mappe som skal deles med denne brukren. Administrator vil ha mulighet for \u00e5 endre alle mapper ved \u00e5 bruke metadata behandler.",
     "ChannelAccessHelp": "Velg kanaler som skal deler med denne brukeren. Administratorer har mulighet til \u00e5 editere p\u00e5 alle kanaler som benytter metadata behandleren.",
@@ -144,26 +163,26 @@
     "LabelSelectUsers": "Velg brukere:",
     "ButtonUpload": "Last opp",
     "HeaderUploadNewImage": "Last opp nytt bilde",
-    "LabelDropImageHere": "Slipp bilde her.",
+    "LabelDropImageHere": "Slipp bilde her",
     "ImageUploadAspectRatioHelp": "1:1 sideforhold anbefales. Kun JPG\/PNG.",
-    "MessageNothingHere": "Ingeting her",
-    "MessagePleaseEnsureInternetMetadata": "P\u00e5se at nedlasting av internet-metadata er sl\u00e5tt p\u00e5",
+    "MessageNothingHere": "Ingeting her.",
+    "MessagePleaseEnsureInternetMetadata": "P\u00e5se at nedlasting av internet-metadata er sl\u00e5tt p\u00e5.",
     "TabSuggested": "Forslag",
     "TabLatest": "Siste",
     "TabUpcoming": "Kommer",
     "TabShows": "Show",
     "TabEpisodes": "Episoder",
-    "TabGenres": "Sjanger",
+    "TabGenres": "Sjangre",
     "TabPeople": "Folk",
     "TabNetworks": "Nettverk",
-    "HeaderUsers": "Bruker",
+    "HeaderUsers": "Brukere",
     "HeaderFilters": "Filtre",
     "ButtonFilter": "Filter",
     "OptionFavorite": "Favoritter",
     "OptionLikes": "Liker",
     "OptionDislikes": "Misliker",
     "OptionActors": "Skuespillere",
-    "OptionGuestStars": "Gjeste-opptredelser",
+    "OptionGuestStars": "Gjeste-opptredener",
     "OptionDirectors": "Regis\u00f8r",
     "OptionWriters": "Manus",
     "OptionProducers": "Produsent",
@@ -171,19 +190,19 @@
     "HeaderNextUp": "Neste",
     "NoNextUpItemsMessage": "Ingen funnet. Begyn \u00e5 se det du har",
     "HeaderLatestEpisodes": "Siste episoder",
-    "HeaderPersonTypes": "Person Typer:",
+    "HeaderPersonTypes": "Persontyper:",
     "TabSongs": "Sanger",
     "TabAlbums": "Album",
     "TabArtists": "Artister",
     "TabAlbumArtists": "Album Artister",
     "TabMusicVideos": "Musikk-videoer",
     "ButtonSort": "Sorter",
-    "HeaderSortBy": "Sorter etter",
+    "HeaderSortBy": "Sorter etter:",
     "HeaderSortOrder": "Sorter Etter:",
     "OptionPlayed": "Sett",
     "OptionUnplayed": "Ikke sett",
-    "OptionAscending": "Oppover",
-    "OptionDescending": "Nedover",
+    "OptionAscending": "\u00d8kende",
+    "OptionDescending": "Synkende",
     "OptionRuntime": "Spilletid",
     "OptionReleaseDate": "Uttgitt dato",
     "OptionPlayCount": "Antall avspillinger",
@@ -192,45 +211,45 @@
     "OptionAlbumArtist": "Album Artist",
     "OptionArtist": "Artist",
     "OptionAlbum": "Album",
-    "OptionTrackName": "L\u00e5navn",
+    "OptionTrackName": "L\u00e5tnavn",
     "OptionCommunityRating": "Community Rangering",
     "OptionNameSort": "Navn",
     "OptionFolderSort": "Mapper",
     "OptionBudget": "Budsjett",
     "OptionRevenue": "Inntjening",
     "OptionPoster": "Plakat",
-    "OptionPosterCard": "Poster card",
-    "OptionBackdrop": "Backdrop",
+    "OptionPosterCard": "Plakatkort",
+    "OptionBackdrop": "Bakgrunn",
     "OptionTimeline": "Tidslinje",
     "OptionThumb": "Thumb",
-    "OptionThumbCard": "Thumb card",
+    "OptionThumbCard": "Thumb-kort",
     "OptionBanner": "Banner",
-    "OptionCriticRating": "Kritiker Vurdering",
+    "OptionCriticRating": "Kritikervurdering",
     "OptionVideoBitrate": "Video bitrate",
-    "OptionResumable": "Fortsettelse",
+    "OptionResumable": "Kan fortsettes",
     "ScheduledTasksHelp": "Klikk p\u00e5 en oppgave for \u00e5 tilpasse tidsplan",
-    "ScheduledTasksTitle": "Tidsplan Oppgaver",
+    "ScheduledTasksTitle": "Planlagte Oppgaver",
     "TabMyPlugins": "Mine programtillegg",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Programtillegg",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatiske oppdateringer",
     "HeaderNowPlaying": "Spiller n\u00e5",
     "HeaderLatestAlbums": "Siste album",
     "HeaderLatestSongs": "Siste l\u00e5ter",
     "HeaderRecentlyPlayed": "Nylig avspilt",
     "HeaderFrequentlyPlayed": "Ofte avspilt",
-    "DevBuildWarning": "Dev builds er \u00e5 anses som p\u00e5 kanten. Disse har ikke blitt testet. Dette vil kunne medf\u00f8re til at applikasjonen kan krasje og komplette funksjoner ikke fungerer.",
-    "LabelVideoType": "Video-type",
+    "DevBuildWarning": "Dev builds er \u00e5 anses som ustabile. Disse har ikke blitt testet. Dette vil kunne medf\u00f8re til at applikasjonen kan krasje og komplette funksjoner ikke fungerer.",
+    "LabelVideoType": "Video-type:",
     "OptionBluray": "Bluray",
-    "OptionDvd": "Dvd",
+    "OptionDvd": "DVD",
     "OptionIso": "ISO",
-    "Option3D": "3d",
+    "Option3D": "3D",
     "LabelFeatures": "Funksjoner:",
     "LabelService": "Service:",
     "LabelStatus": "Status:",
     "LabelVersion": "Versjon:",
     "LabelLastResult": "Siste resultat:",
-    "OptionHasSubtitles": "undertekster",
+    "OptionHasSubtitles": "Undertekster",
     "OptionHasTrailer": "Trailer",
     "OptionHasThemeSong": "Temasang",
     "OptionHasThemeVideo": "Temavideo",
@@ -241,16 +260,16 @@
     "LabelArtistsHelp": "Skill flere med semikolon ;",
     "HeaderLatestMovies": "Siste Filmer",
     "HeaderLatestTrailers": "Siste Trailers",
-    "OptionHasSpecialFeatures": "Spesial Funksjoner",
-    "OptionImdbRating": "IMDB Rangering",
+    "OptionHasSpecialFeatures": "Spesialfunksjoner",
+    "OptionImdbRating": "IMDb Rangering",
     "OptionParentalRating": "Foreldresensur",
-    "OptionPremiereDate": "premieredato",
-    "TabBasic": "Basic",
+    "OptionPremiereDate": "Premieredato",
+    "TabBasic": "Enkel",
     "TabAdvanced": "Avansert",
     "HeaderStatus": "Status",
     "OptionContinuing": "Fortsetter",
     "OptionEnded": "Avsluttet",
-    "HeaderAirDays": "Lanseringsdager",
+    "HeaderAirDays": "Vises dager",
     "OptionSunday": "S\u00f8ndag",
     "OptionMonday": "Mandag",
     "OptionTuesday": "Tirsdag",
@@ -260,50 +279,50 @@
     "OptionSaturday": "L\u00f8rdag",
     "HeaderManagement": "Strying",
     "LabelManagement": "Administrasjon",
-    "OptionMissingImdbId": "Mangler IMDb id",
-    "OptionMissingTvdbId": "Mangler TVDB id",
+    "OptionMissingImdbId": "Mangler IMDb ID",
+    "OptionMissingTvdbId": "Mangler TVDB ID",
     "OptionMissingOverview": "Mangler oversikt",
-    "OptionFileMetadataYearMismatch": "Fil\/Metadata \u00e5r Mismatch",
+    "OptionFileMetadataYearMismatch": "Fil\/Metadata \u00e5r mismatch",
     "TabGeneral": "Genrelt",
     "TitleSupport": "Support",
     "TabLog": "Logg",
     "TabAbout": "Om",
     "TabSupporterKey": "Supporter-n\u00f8kkel",
     "TabBecomeSupporter": "Bli en supporter",
-    "MediaBrowserHasCommunity": "Media Browser har ett blomstrende fellesskap av brukere og bidragsytere.",
-    "CheckoutKnowledgeBase": "Sjekk ut v\u00e5r kunnskaps base for \u00e5 hjelpe deg med \u00e5 f\u00e5 best utbytte av Media Browser",
+    "MediaBrowserHasCommunity": "Media Browser har et blomstrende fellesskap av brukere og bidragsytere.",
+    "CheckoutKnowledgeBase": "Sjekk ut v\u00e5r kunnskapsbase for \u00e5 hjelpe deg med \u00e5 f\u00e5 best utbytte av Media Browser",
     "SearchKnowledgeBase": "S\u00f8k kunnskapsbasen",
     "VisitTheCommunity": "Bes\u00f8k oss",
     "VisitMediaBrowserWebsite": "Bes\u00f8k Media Browsers nettside",
-    "VisitMediaBrowserWebsiteLong": "Bes\u00f8k Media Browser sin side for \u00e5 f\u00e5 de siste nyhetene og for \u00e5 f\u00f8lge med p\u00e5 utviklerbloggen.",
+    "VisitMediaBrowserWebsiteLong": "Bes\u00f8k Media Browsers nettside for \u00e5 f\u00e5 de siste nyhetene og for \u00e5 f\u00f8lge med p\u00e5 utviklerbloggen.",
     "OptionHideUser": "Skjul brukere fra logginn-skjermen",
-    "OptionHideUserFromLoginHelp": "Useful for private or hidden administrator accounts. The user will need to sign in manually by entering their username and password.",
+    "OptionHideUserFromLoginHelp": "Praktisk for private eller skjulte administratorer. Brukeren vil m\u00e5tte logge inn manuelt ved \u00e5 skrive inn brukernavn og passord.",
     "OptionDisableUser": "Deaktiver denne brukeren",
-    "OptionDisableUserHelp": "Hvis avsl\u00e5tt, serveren vil ikke godta noen forbindelser fra denne brukeren. eksisterende forbindelser vil bli br\u00e5tt avsluttet.",
+    "OptionDisableUserHelp": "Hvis avsl\u00e5tt vil ikke serveren godta noen forbindelser fra denne brukeren. Eksisterende forbindelser vil avsluttes umiddelbart.",
     "HeaderAdvancedControl": "Avansert Kontroll",
     "LabelName": "Navn",
-    "ButtonHelp": "Help",
+    "ButtonHelp": "Hjelp",
     "OptionAllowUserToManageServer": "TIllatt denne brukeren \u00e5 administrere serveren",
-    "HeaderFeatureAccess": "Funksjon Tilgang",
-    "OptionAllowMediaPlayback": "Allow media playback",
-    "OptionAllowBrowsingLiveTv": "Allow Live TV access",
-    "OptionAllowDeleteLibraryContent": "Allow media deletion",
-    "OptionAllowManageLiveTv": "Allow Live TV recording management",
+    "HeaderFeatureAccess": "Funksjonstilgang",
+    "OptionAllowMediaPlayback": "Tillate avspilling av media",
+    "OptionAllowBrowsingLiveTv": "Tillate Live TV",
+    "OptionAllowDeleteLibraryContent": "Tillate sletting av media",
+    "OptionAllowManageLiveTv": "Tillate administrasjon av Live TV",
     "OptionAllowRemoteControlOthers": "Tillat fjernstyring av andre brukere",
-    "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices",
-    "OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.",
-    "HeaderRemoteControl": "Remote Control",
-    "OptionMissingTmdbId": "Mangler Tmdb id",
+    "OptionAllowRemoteSharedDevices": "Tillate fjernstyring av delte enheter",
+    "OptionAllowRemoteSharedDevicesHelp": "DLNA-enheter betraktes som delte inntil en bruker begynner \u00e5 styre dem.",
+    "HeaderRemoteControl": "Fjernstyring",
+    "OptionMissingTmdbId": "Mangler Tmdb ID",
     "OptionIsHD": "HD",
     "OptionIsSD": "SD",
     "OptionMetascore": "Metascore",
     "ButtonSelect": "Velg",
-    "ButtonGroupVersions": "Gruppe Versjoner",
-    "ButtonAddToCollection": "Add to Collection",
+    "ButtonGroupVersions": "Gruppeversjoner",
+    "ButtonAddToCollection": "Legg til samling",
     "PismoMessage": "Utnytte Pismo File Mount gjennom en donert lisens.",
     "TangibleSoftwareMessage": "Utnytte konkrete l\u00f8sninger Java \/ C # omformere gjennom en donert lisens.",
     "HeaderCredits": "Credits",
-    "PleaseSupportOtherProduces": "Vennligst gi st\u00f8tte til andre gratis produkter vi benytter:",
+    "PleaseSupportOtherProduces": "Vennligst gi st\u00f8tte til andre gratisprodukter vi benytter:",
     "VersionNumber": "Versjon {0}",
     "TabPaths": "Stier",
     "TabServer": "Server",
@@ -314,47 +333,47 @@
     "OptionBeta": "Beta",
     "OptionDev": "Dev (Ustabil)",
     "LabelAllowServerAutoRestart": "Tillat at serveren restartes automatisk for \u00e5 gjennomf\u00f8re oppdateringer",
-    "LabelAllowServerAutoRestartHelp": "Serveren vil kun restartes i inaktiv perioder, n\u00e5r ingen brukere er aktive.",
+    "LabelAllowServerAutoRestartHelp": "Serveren vil kun restartes i inaktive perioder, n\u00e5r ingen brukere er aktive.",
     "LabelEnableDebugLogging": "Sl\u00e5 p\u00e5 debug logging.",
     "LabelRunServerAtStartup": "Start server ved maskin-oppstart",
     "LabelRunServerAtStartupHelp": "Dette vil starte ikonet ved oppstart av Windows. For \u00e5 starte Windows-tjeneste, fjerner du denne markering og kj\u00f8rer tjenesten fra kontrollpanelet i Windows. V\u00e6r oppmerksom p\u00e5 at du ikke kan kj\u00f8re begge p\u00e5 samme tid, s\u00e5 du m\u00e5 g\u00e5 ut av ikonet f\u00f8r du starter tjenesten.",
     "ButtonSelectDirectory": "Velg Katalog",
     "LabelCustomPaths": "Angi egendefinerte stier der du \u00f8nsker. La feltene st\u00e5 tomme for \u00e5 bruke standardinnstillingene.",
     "LabelCachePath": "Buffer sti:",
-    "LabelCachePathHelp": "Definer en tilpasset lokalisering for server cashe filer, som bilder.",
+    "LabelCachePathHelp": "Definer en tilpasset lokalisering for server cache filer, som bilder.",
     "LabelImagesByNamePath": "Bilder etter navn sti:",
-    "LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, genre and studio images.",
+    "LabelImagesByNamePathHelp": "Angi en egen katalog for nedlastede bilder for skuespiller, sjanger og studio.",
     "LabelMetadataPath": "Metadata sti:",
     "LabelMetadataPathHelp": "Definer en tilpasset lokalisering for nedlastede artwork og metadata, hvis ikke skjer lagring innen media mappene.",
-    "LabelTranscodingTempPath": "Transcoding midlertidig sti",
+    "LabelTranscodingTempPath": "Sti for midlertidig transcoding:",
     "LabelTranscodingTempPathHelp": "Denne mappen inneholder fungerende filer som blir brukt av transcoderen. Spesifiser en tilpasset sti eller la det st\u00e5 tomt for \u00e5 benytte serverens standard sti.",
-    "TabBasics": "Basic",
+    "TabBasics": "Basics",
     "TabTV": "TV",
     "TabGames": "Spill",
     "TabMusic": "Musikk",
     "TabOthers": "Andre",
-    "HeaderExtractChapterImagesFor": "Pakk ut kapittel bilder for:",
+    "HeaderExtractChapterImagesFor": "Pakk ut kapittelbilder for:",
     "OptionMovies": "Filmer",
     "OptionEpisodes": "Episoder",
     "OptionOtherVideos": "Andre Videoer",
     "TitleMetadata": "Metadata",
-    "LabelAutomaticUpdates": "Enable automatic updates",
+    "LabelAutomaticUpdates": "Skru p\u00e5 automatiske oppdateringer",
     "LabelAutomaticUpdatesTmdb": "Aktiver automatisk oppdateringer fra TheMovieDB.org",
     "LabelAutomaticUpdatesTvdb": "Aktiver automatisk oppdateringer fra TheTVDB.com",
-    "LabelAutomaticUpdatesFanartHelp": "Hvis aktivert vil nye bilder bli nedlastet automatisk n\u00e5r de blir lagt til fanar.tv. Eksisterende bilder vil ikke bli erstattet.",
+    "LabelAutomaticUpdatesFanartHelp": "Hvis aktivert vil nye bilder bli nedlastet automatisk n\u00e5r de blir lagt til fanart.tv. Eksisterende bilder vil ikke bli erstattet.",
     "LabelAutomaticUpdatesTmdbHelp": "Hvis aktivert vil nye bilder bli nedlastet automatisk n\u00e5r de blir lagt til i TheMovieDB.org. Ekisterende bilder vil ikke bli erstattet.",
     "LabelAutomaticUpdatesTvdbHelp": "Hvis aktivert vil nye bilder bli nedlastet automatisk n\u00e5r de blir lagt til i TheTVDB.com. Ekisterende bilder vil ikke bli erstattet.",
-    "LabelFanartApiKey": "Personal api key:",
-    "LabelFanartApiKeyHelp": "Requests to fanart without a personal API key return results that were approved over 7 days ago. With a personal API key that drops to 48 hours and if you are also a fanart VIP member that will further drop to around 10 minutes.",
-    "ExtractChapterImagesHelp": "Extracting chapter images will allow clients to display graphical scene selection menus. The process can be slow, cpu-intensive and may require several gigabytes of space. It runs when videos are discovered, and also as a nightly scheduled task. The schedule is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.",
+    "LabelFanartApiKey": "Personlig API-n\u00f8kkel:",
+    "LabelFanartApiKeyHelp": "Foresp\u00f8rsler for fanart uten personlig API-n\u00f8kkel vil gi resultater som ble godkjent for over 7 dager siden. Med en personlig API-n\u00f8kkel synker dette til 48 timer, og med et fanart VIP-medlemskap synker det ytterliger til ca. 10 minutter.",
+    "ExtractChapterImagesHelp": "Ved \u00e5 hente ut kapittelbilder kan klientene vise grafiske menyer for valg av sccene. Denne prosessen kan v\u00e6re treg, CPU-intensiv og krever flerfoldige gigabytes med plass. Prosessen kj\u00f8res n\u00e5r videoer scannes, og kan ogs\u00e5 kj\u00f8res om natten. Dette er konfigurerbart under Planlagte Aktiviteter. Det er ikke anbefalt \u00e5 kj\u00f8re dette mens serveren er i bruk til visning av media.",
     "LabelMetadataDownloadLanguage": "Foretrukket nedlastingsspr\u00e5k:",
     "ButtonAutoScroll": "Auto-scroll",
     "LabelImageSavingConvention": "Bilde besparende konvensjon:",
-    "LabelImageSavingConventionHelp": "Media Browser gjengjenner bilder fra de fleste media applikasjonene. Ved valg av dine nedlastings konvensjoner er nyttig hvis du i tillegg benytter andre produkter.",
+    "LabelImageSavingConventionHelp": "Media Browser gjenkjenner bilder fra de fleste media applikasjonene. Ved valg av dine nedlastings konvensjoner er nyttig hvis du i tillegg benytter andre produkter.",
     "OptionImageSavingCompatible": "Kompatibel - Media Browser\/Kodi\/Plex",
     "OptionImageSavingStandard": "Standard - MB2",
     "ButtonSignIn": "Logg inn",
-    "TitleSignIn": "Logg Inn",
+    "TitleSignIn": "Logg inn",
     "HeaderPleaseSignIn": "Vennligst Logg inn",
     "LabelUser": "Bruker:",
     "LabelPassword": "Passord:",
@@ -388,8 +407,8 @@
     "OptionRecordOnlyNewEpisodes": "Ta opptak kun av nye episoder",
     "HeaderDays": "Dager",
     "HeaderActiveRecordings": "Aktive opptak",
-    "HeaderLatestRecordings": "Siste Opptak",
-    "HeaderAllRecordings": "Alle Opptak",
+    "HeaderLatestRecordings": "Siste opptak",
+    "HeaderAllRecordings": "Alle opptak",
     "ButtonPlay": "Spill",
     "ButtonEdit": "Rediger",
     "ButtonRecord": "Opptak",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Antall dager av guide data som skal lastes ned",
     "LabelNumberOfGuideDaysHelp": "Nedlasting av guide data for flere dager gir muligheten for \u00e5 planlegge i forveien og for \u00e5 se flere listinger. Dette vil ogs\u00e5 ta lengre tid for nedlasting. Auto vil velge basert p\u00e5 antall kanaler.",
-    "LabelActiveService": "Aktive Tjenester:",
-    "LabelActiveServiceHelp": "Flere TV programtillegg kan bli installert, men kun en kan v\u00e6re aktiv.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "En Live TV tilbyder trengs for \u00e5 kunne fortsette.",
     "LiveTvPluginRequiredHelp": "Vennligst installer en av v\u00e5re tilgjengelige programtillegg, f.eks Next Pvr eller ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Tilpass for media type:",
@@ -416,21 +434,21 @@
     "OptionDownloadArtImage": "Art",
     "OptionDownloadPrimaryImage": "Prim\u00e6r",
     "HeaderFetchImages": "Hent Bilder:",
-    "HeaderImageSettings": "Bilde Innstillinger",
+    "HeaderImageSettings": "Bildeinnstillinger",
     "TabOther": "Andre",
     "LabelMaxBackdropsPerItem": "Maks antall av backdrops for hvert element:",
     "LabelMaxScreenshotsPerItem": "Maks antall av screenshots for hvert element:",
     "LabelMinBackdropDownloadWidth": "Minimum backdrop nedlastings bredde:",
     "LabelMinScreenshotDownloadWidth": "Minimum nedlasted screenshot bredde:",
-    "ButtonAddScheduledTaskTrigger": "Add Trigger",
-    "HeaderAddScheduledTaskTrigger": "Add Trigger",
-    "ButtonAdd": "Legg Til",
+    "ButtonAddScheduledTaskTrigger": "Legg til trigger",
+    "HeaderAddScheduledTaskTrigger": "Legg til trigger",
+    "ButtonAdd": "Legg til",
     "LabelTriggerType": "Trigger Type:",
     "OptionDaily": "Daglig",
     "OptionWeekly": "Ukentlig",
-    "OptionOnInterval": "P\u00e5 ett intervall",
-    "OptionOnAppStartup": "Ved applikasjon oppstart",
-    "OptionAfterSystemEvent": "Etter ett system hendelse",
+    "OptionOnInterval": "P\u00e5 intervall",
+    "OptionOnAppStartup": "Ved applikasjonens oppstart",
+    "OptionAfterSystemEvent": "Etter systemhendelse",
     "LabelDay": "Dag:",
     "LabelTime": "Tid:",
     "LabelEvent": "Hendelse:",
@@ -444,9 +462,9 @@
     "TitleMediaLibrary": "Media-bibliotek",
     "TabFolders": "Mapper",
     "TabPathSubstitution": "Sti erstatter",
-    "LabelSeasonZeroDisplayName": "Sesong 0 visningsnavn",
+    "LabelSeasonZeroDisplayName": "Sesong 0 visningsnavn:",
     "LabelEnableRealtimeMonitor": "Aktiver sanntids monitorering",
-    "LabelEnableRealtimeMonitorHelp": "Endinger vil bli prossesert umiddelbart, til st\u00f8ttede file systemer.",
+    "LabelEnableRealtimeMonitorHelp": "Endinger vil bli prossesert umiddelbart, til st\u00f8ttede filsystemer.",
     "ButtonScanLibrary": "S\u00f8k Gjennom Bibliotek",
     "HeaderNumberOfPlayers": "Spillere:",
     "OptionAnyNumberOfPlayers": "Noen",
@@ -454,13 +472,13 @@
     "Option2Player": "2+",
     "Option3Player": "3+",
     "Option4Player": "4+",
-    "HeaderMediaFolders": "Media Mapper",
-    "HeaderThemeVideos": "Tema Videoer",
-    "HeaderThemeSongs": "Tema Sanger",
+    "HeaderMediaFolders": "Mediemapper",
+    "HeaderThemeVideos": "Temavideoer",
+    "HeaderThemeSongs": "Temasanger",
     "HeaderScenes": "Scener",
     "HeaderAwardsAndReviews": "Priser og anmeldelser",
     "HeaderSoundtracks": "Lydspor",
-    "HeaderMusicVideos": "Musikk Videoer",
+    "HeaderMusicVideos": "Musikkvideoer",
     "HeaderSpecialFeatures": "Spesielle Funksjoner",
     "HeaderCastCrew": "Mannskap",
     "HeaderAdditionalParts": "Tilleggsdeler",
@@ -468,30 +486,30 @@
     "ButtonPlayTrailer": "Trailer",
     "LabelMissing": "Mangler",
     "LabelOffline": "Offline",
-    "PathSubstitutionHelp": "Sti erstatninger er brukt for \u00e5 kartlegge en bane p\u00e5 serveren til en bane som kundene er i stand til \u00e5 f\u00e5 tilgang. Ved \u00e5 la kundene direkte tilgang til media p\u00e5 serveren kan de v\u00e6re i stand til \u00e5 spille dem direkte over nettverket, og unng\u00e5 \u00e5 bruke server ressurser til \u00e5 streame og omkode dem.",
+    "PathSubstitutionHelp": "Sti erstatninger er brukt for \u00e5 koble en katalog p\u00e5 serveren til en katalog som brukeren har tilgang til. Ved \u00e5 gi brukerne direkte tilgang til media p\u00e5 serveren kan de v\u00e6re i stand til \u00e5 spille dem direkte over nettverket, og unng\u00e5 \u00e5 bruke serverens ressurser til \u00e5 streame og transcode dem.",
     "HeaderFrom": "Fra",
     "HeaderTo": "Til",
     "LabelFrom": "Fra:",
     "LabelFromHelp": "Eksempel: D:\\Filmer (P\u00e5 serveren)",
     "LabelTo": "Til:",
-    "LabelToHelp": "Eksempel: \\\\MinServerFilmer (en sti som klienter kan f\u00e5 tilgang til)",
+    "LabelToHelp": "Eksempel: \\\\MinServer\\Filmer (en sti som klienter kan f\u00e5 tilgang til)",
     "ButtonAddPathSubstitution": "Legg til erstatter",
     "OptionSpecialEpisode": "Spesielle",
     "OptionMissingEpisode": "Mangler Episoder",
     "OptionUnairedEpisode": "Kommende Episoder",
     "OptionEpisodeSortName": "Episode Etter Navn",
-    "OptionSeriesSortName": "Serie Navn",
+    "OptionSeriesSortName": "Serienavn",
     "OptionTvdbRating": "Tvdb Rangering",
-    "HeaderTranscodingQualityPreference": "\u00d8nsket kvalitet for transkoding",
-    "OptionAutomaticTranscodingHelp": "Serveren vil bestemme kvalitet og hastighet",
+    "HeaderTranscodingQualityPreference": "\u00d8nsket kvalitet for transcoding",
+    "OptionAutomaticTranscodingHelp": "Serveren bestemmer kvalitet og hastighet",
     "OptionHighSpeedTranscodingHelp": "Lavere kvalitet, men raskere encoding",
     "OptionHighQualityTranscodingHelp": "H\u00f8yere kvalitet, men saktere encoding",
-    "OptionMaxQualityTranscodingHelp": "Beste kvalitet med saktere encoding og h\u00f8y CPU bruk",
+    "OptionMaxQualityTranscodingHelp": "Beste kvalitet med saktere encoding og h\u00f8y CPU-bruk",
     "OptionHighSpeedTranscoding": "H\u00f8yere hastighet",
     "OptionHighQualityTranscoding": "H\u00f8yere kvalitet",
     "OptionMaxQualityTranscoding": "Maks kvalitet",
-    "OptionEnableDebugTranscodingLogging": "Sl\u00e5 p\u00e5 debug transcoding logging",
-    "OptionEnableDebugTranscodingLoggingHelp": "Dette vil lage veldig lange log filer og er kun anbefalt for feils\u00f8king.",
+    "OptionEnableDebugTranscodingLogging": "Sl\u00e5 p\u00e5 debug-logging av transcoding",
+    "OptionEnableDebugTranscodingLoggingHelp": "Dette vil lage veldig store log-filer og er kun anbefalt ved feils\u00f8king.",
     "EditCollectionItemsHelp": "Legg til eller fjern hvilken som helst film, serie, album, bok eller spill som du \u00f8nsker \u00e5 gruppere innen denne samlingen.",
     "HeaderAddTitles": "Legg til Titler",
     "LabelEnableDlnaPlayTo": "Sl\u00e5 p\u00e5 DLNA Play To",
@@ -501,52 +519,52 @@
     "LabelEnableDlnaClientDiscoveryInterval": "Klient oppdaterings interval (Sekunder)",
     "LabelEnableDlnaClientDiscoveryIntervalHelp": "Bestemmer varigheten i sekunder mellom SSDP s\u00f8k utf\u00f8rt av Media Browser.",
     "HeaderCustomDlnaProfiles": "Tilpassede Profiler",
-    "HeaderSystemDlnaProfiles": "System Profiler",
-    "CustomDlnaProfilesHelp": "Lag en tilpasset profil for \u00e5 sette en ny enhet til \u00e5 overkj\u00f8re en system profil.",
-    "SystemDlnaProfilesHelp": "System profiler er read-only. Endinger til ett system profil vil bli lagret til en ny tilpasset profil.",
+    "HeaderSystemDlnaProfiles": "Systemprofiler",
+    "CustomDlnaProfilesHelp": "Lag en tilpasset profil for \u00e5 sette en ny enhet til \u00e5 overstyre en system profil.",
+    "SystemDlnaProfilesHelp": "Systemprofiler er read-only. Endinger p\u00e5 en systemprofil vil bli lagret til en ny tilpasset profil.",
     "TitleDashboard": "Dashbord",
     "TabHome": "Hjem",
     "TabInfo": "Info",
     "HeaderLinks": "Lenker",
-    "HeaderSystemPaths": "System Stier",
+    "HeaderSystemPaths": "Systemstier",
     "LinkCommunity": "Samfunn",
     "LinkGithub": "Github",
-    "LinkApi": "Api",
-    "LinkApiDocumentation": "Api Dokumentasjon",
+    "LinkApi": "API",
+    "LinkApiDocumentation": "API Dokumentasjon",
     "LabelFriendlyServerName": "Vennlig server navn:",
     "LabelFriendlyServerNameHelp": "Dette navnet vil bli brukt for \u00e5 identifisere denne serveren. Hvis feltet er tomt, vil maskinens navn bli brukt.",
-    "LabelPreferredDisplayLanguage": "Foretrukket skjerm spr\u00e5k:",
+    "LabelPreferredDisplayLanguage": "Foretrukket spr\u00e5k:",
     "LabelPreferredDisplayLanguageHelp": "Oversetting av Media Browser er ett p\u00e5g\u00e5ende prosjekt og er enda ikke fullstendig ferdig.",
     "LabelReadHowYouCanContribute": "Les mer om hvordan du kan bidra.",
     "HeaderNewCollection": "Ny Samling",
     "ButtonSubmit": "Send",
     "ButtonCreate": "Opprett",
-    "LabelCustomCss": "Custom css:",
-    "LabelCustomCssHelp": "Apply your own custom css to the web interface.",
-    "LabelLocalHttpServerPortNumber": "Local http port number:",
-    "LabelLocalHttpServerPortNumberHelp": "tcp port nummeret som Media Browser sin https server skal bindes mot.",
-    "LabelPublicHttpPort": "Public http port number:",
-    "LabelPublicHttpPortHelp": "The public port number that should be mapped to the local http port.",
-    "LabelPublicHttpsPort": "Public https port number:",
-    "LabelPublicHttpsPortHelp": "The public port number that should be mapped to the local https port.",
-    "LabelEnableHttps": "Report https as external address",
-    "LabelEnableHttpsHelp": "If enabled, the server will report an https url to clients as it's external address. This may break clients that do not yet support https.",
-    "LabelHttpsPort": "Local https port number:",
-    "LabelHttpsPortHelp": "The tcp port number that Media Browser's https server should bind to.",
-    "LabelWebSocketPortNumber": "Web socker port nummer:",
-    "LabelEnableAutomaticPortMap": "Aktiver automatisk port mapping",
-    "LabelEnableAutomaticPortMapHelp": "Fors\u00f8k automatisk mapping av den offentlige port til den lokale port via UPnP. Dette kan fungerer d\u00e5rlig med noen ruter modeller.",
-    "LabelExternalDDNS": "External WAN Address:",
-    "LabelExternalDDNSHelp": "If you have a dynamic DNS enter it here. Media Browser apps will use it when connecting remotely. Leave empty for automatic detection.",
+    "LabelCustomCss": "Tilpass CSS:",
+    "LabelCustomCssHelp": "Bruk din egen CSS p\u00e5 web-grensesnittet.",
+    "LabelLocalHttpServerPortNumber": "Lokal HTTP port:",
+    "LabelLocalHttpServerPortNumberHelp": "TCP port nummeret som Media Browsers https server skal bindes mot.",
+    "LabelPublicHttpPort": "Offentlig HTTP port:",
+    "LabelPublicHttpPortHelp": "Den offentlige porten som kobles til den lokale porten.",
+    "LabelPublicHttpsPort": "Offentlig HTTPS port:",
+    "LabelPublicHttpsPortHelp": "Den offentlige porten som den lokale porten kobles til.",
+    "LabelEnableHttps": "Oppgi HTTPS som ekstern adresse",
+    "LabelEnableHttpsHelp": "Hvis denne er aktivert vil serveren oppgi en HTTPS URL som sin eksterne adresse. Dette kan \u00f8delegge for klienter som enda ikke st\u00f8tter HTTPS.",
+    "LabelHttpsPort": "Lokal HTTPS port:",
+    "LabelHttpsPortHelp": "TCP port som Media Browsers HTTPS server skal benytte.",
+    "LabelWebSocketPortNumber": "Web socket portnummer:",
+    "LabelEnableAutomaticPortMap": "Aktiver automatisk portmapping",
+    "LabelEnableAutomaticPortMapHelp": "Fors\u00f8k automatisk mapping av den offentlige port til den lokale port via UPnP. Dette fungerer ikke med alle rutere.",
+    "LabelExternalDDNS": "Ekstern WAN-adresse:",
+    "LabelExternalDDNSHelp": "Hvis du har en dynamisk DNS, angi denne her. Media Browser applikasjoneer bruker den n\u00e5r de kobler til fra utsiden. La dette feltet v\u00e6re tomt for automatisk innhenting.",
     "TabResume": "Forsette",
     "TabWeather": "V\u00e6r",
-    "TitleAppSettings": "App Innstillinger",
-    "LabelMinResumePercentage": "Minimum fortsettelses prosent:",
-    "LabelMaxResumePercentage": "Maksimum fortsettelses prosent:",
+    "TitleAppSettings": "App-innstillinger",
+    "LabelMinResumePercentage": "Minimum fortsettelsesprosent:",
+    "LabelMaxResumePercentage": "Maksimum fortsettelsesprosent:",
     "LabelMinResumeDuration": "Minmimum fortsettelses varighet (sekunder)",
     "LabelMinResumePercentageHelp": "Titler blir antatt som ikke avspilt hvis de stopper f\u00f8r denne tiden",
     "LabelMaxResumePercentageHelp": "Titler blir antatt som fullstendig avspilt hvis de stopper etter denne tiden",
-    "LabelMinResumeDurationHelp": "Titler kortere enn dette vil ikke forsette.",
+    "LabelMinResumeDurationHelp": "Titler kortere enn dette kan ikke fortsettes.",
     "TitleAutoOrganize": "Auto-Organisering",
     "TabActivityLog": "Aktivitetslog",
     "HeaderName": "Navn",
@@ -558,7 +576,7 @@
     "LabelCompleted": "Fullf\u00f8rt",
     "LabelFailed": "Feilet",
     "LabelSkipped": "Hoppet over",
-    "HeaderEpisodeOrganization": "Episode Organisering",
+    "HeaderEpisodeOrganization": "Organisering av episoder",
     "LabelSeries": "Serie:",
     "LabelSeasonNumber": "Sesong nummer:",
     "LabelEpisodeNumber": "Episode nummer:",
@@ -567,12 +585,12 @@
     "HeaderSupportTheTeam": "St\u00f8tt Media Browser Teamet",
     "LabelSupportAmount": "Sum (USD)",
     "HeaderSupportTheTeamHelp": "Bidra til \u00e5 sikre fortsatt utvikling av dette prosjektet ved \u00e5 donere. En del av alle donasjoner vil v\u00e6re bidratt til andre gratis verkt\u00f8y vi er avhengige av.",
-    "ButtonEnterSupporterKey": "Skriv supporter n\u00f8kkel",
-    "DonationNextStep": "N\u00e5r du er ferdig, kan du g\u00e5 tilbake og skriv inn din support n\u00f8kkel, som du vil motta p\u00e5 e-post.",
-    "AutoOrganizeHelp": "Auto-organisere monitorerer dine nedlastingsmapper for nye filer og flytter dem til medie kataloger.",
-    "AutoOrganizeTvHelp": "TV file organisering vil kun legge til episoder til eksisterende episoder. Den vil ikke lage nye serie mapper.",
-    "OptionEnableEpisodeOrganization": "Aktiver ny episode organisering",
-    "LabelWatchFolder": "Se p\u00e5 Mappe:",
+    "ButtonEnterSupporterKey": "Skriv supportn\u00f8kkel",
+    "DonationNextStep": "N\u00e5r du er ferdig, kan du g\u00e5 tilbake og skriv inn din supportn\u00f8kkel, som du vil motta p\u00e5 e-post.",
+    "AutoOrganizeHelp": "Auto-organisere monitorerer dine nedlastingsmapper for nye filer og flytter dem til riktig mediakatalog.",
+    "AutoOrganizeTvHelp": "TV organisering vil kun legge til episoder til eksisterende serier. Den vil ikke lage nye serie-mapper.",
+    "OptionEnableEpisodeOrganization": "Aktiver organisering av ny episode",
+    "LabelWatchFolder": "Se p\u00e5 mappe:",
     "LabelWatchFolderHelp": "Serveren vil hente denne mappen under 'Organiser nye mediefiler' planlagte oppgaven.",
     "ButtonViewScheduledTasks": "Se p\u00e5 planlagte oppgaver",
     "LabelMinFileSizeForOrganize": "Minimum fil st\u00f8rrelse (MB):",
@@ -599,8 +617,8 @@
     "HeaderHelpImproveMediaBrowser": "Hjelp \u00e5 forbedre Media Browser",
     "HeaderRunningTasks": "Kj\u00f8rende oppgaver",
     "HeaderActiveDevices": "Aktive enheter",
-    "HeaderPendingInstallations": "ventede installasjoner",
-    "HeaderServerInformation": "Server Information",
+    "HeaderPendingInstallations": "Installeringer i k\u00f8",
+    "HeaderServerInformation": "Serverinformasjon",
     "ButtonRestartNow": "Restart N\u00e5",
     "ButtonRestart": "Restart",
     "ButtonShutdown": "Sl\u00e5 Av",
@@ -611,64 +629,65 @@
     "ServerUpToDate": "Media Browser Server er oppdatert",
     "LabelComponentsUpdated": "F\u00f8lgende komponenter har blitt installert eller oppdatert:",
     "MessagePleaseRestartServerToFinishUpdating": "Vennligst restart serveren for \u00e5 fullf\u00f8re installasjon av oppdateringer.",
-    "LabelDownMixAudioScale": "Lyd boost n\u00e5r downmixing:",
+    "LabelDownMixAudioScale": "Lyd boost ved downmixing:",
     "LabelDownMixAudioScaleHelp": "Boost lyd n\u00e5r downmixing. Set til 1 for \u00e5 bevare orginal volum verdi.",
-    "ButtonLinkKeys": "Overf\u00f8r N\u00f8kkel",
-    "LabelOldSupporterKey": "Gammel supporter n\u00f8kkel",
-    "LabelNewSupporterKey": "Ny supporter n\u00f8kkel",
-    "HeaderMultipleKeyLinking": "Overf\u00f8r til ny N\u00f8kkel",
-    "MultipleKeyLinkingHelp": "Bruk dette skjemaet hvis du har mottatt en ny support n\u00f8kkel for \u00e5 overf\u00f8re gamle n\u00f8kkel registreringer til din nye.",
-    "LabelCurrentEmailAddress": "Gjeldende email adresse",
+    "ButtonLinkKeys": "Overf\u00f8r n\u00f8kkel",
+    "LabelOldSupporterKey": "Gammel supportern\u00f8kkel",
+    "LabelNewSupporterKey": "Ny supportern\u00f8kkel",
+    "HeaderMultipleKeyLinking": "Overf\u00f8r til ny n\u00f8kkel",
+    "MultipleKeyLinkingHelp": "Bruk dette skjemaet hvis du har mottatt en ny supportn\u00f8kkel for \u00e5 overf\u00f8re gamle n\u00f8kkelregistreringer til din nye.",
+    "LabelCurrentEmailAddress": "Gjeldende epostadresse",
     "LabelCurrentEmailAddressHelp": "Den aktuelle e-postadressen som den nye n\u00f8kkelen ble sendt.",
     "HeaderForgotKey": "Glemt N\u00f8kkel",
-    "LabelEmailAddress": "e-postadresse",
-    "LabelSupporterEmailAddress": "e-postadressen som ble brukt for \u00e5 kj\u00f8pe n\u00f8kkelen.",
+    "LabelEmailAddress": "Epostadresse",
+    "LabelSupporterEmailAddress": "Epostadressen som ble brukt for \u00e5 kj\u00f8pe n\u00f8kkelen.",
     "ButtonRetrieveKey": "Motta N\u00f8kkel",
-    "LabelSupporterKey": "Supporter N\u00f8kkel (Lim inn fra e-postadresse)",
-    "LabelSupporterKeyHelp": "Skriv inn din supporter n\u00f8kkel for \u00e5 kunne nyte flere fordeler som samfunnet har utviklet for Media Browser.",
-    "MessageInvalidKey": "Supporter n\u00f8kkel mangler eller er feil.",
-    "ErrorMessageInvalidKey": "For eventuelt premiuminnhold for \u00e5 bli registrert, m\u00e5 du ogs\u00e5 v\u00e6re en Media Browser Supporter. Vennligst doner og st\u00f8tt det videre-utviklede av kjerneproduktet. Takk.",
-    "HeaderDisplaySettings": "Visnings Innstillinger",
+    "LabelSupporterKey": "Supporter N\u00f8kkel (Lim inn fra mottatt epost)",
+    "LabelSupporterKeyHelp": "Skriv inn din supporter n\u00f8kkel for \u00e5 kunne nyte flere fordeler som utviklerne har laget for Media Browser.",
+    "MessageInvalidKey": "Supportern\u00f8kkel mangler eller er feil.",
+    "ErrorMessageInvalidKey": "For \u00e5 registrere premium innhold m\u00e5 du v\u00e6re en Media Browser Supporter. Vennligst don\u00e9r og st\u00f8tt videre utvikling av kMedia Server. Takk skal du ha!",
+    "HeaderDisplaySettings": "Visnings innstillinger",
     "TabPlayTo": "Spill Til",
     "LabelEnableDlnaServer": "Sl\u00e5 p\u00e5 Dlna server",
-    "LabelEnableDlnaServerHelp": "Tillat UPnP enheter p\u00e5 ditt nettverk for \u00e5 s\u00f8ke gjennom spill Media Browser innhold.",
+    "LabelEnableDlnaServerHelp": "Tillat UPnP-enheter p\u00e5 ditt nettverk \u00e5 s\u00f8ke gjennom og \u00e5 spille innhold p\u00e5 Media Browser.",
     "LabelEnableBlastAliveMessages": "Spreng levende meldinger",
-    "LabelEnableBlastAliveMessagesHelp": "Sl\u00e5 p\u00e5 hvis serveren ikke detekterer p\u00e5litelighet fra andre UPnP enheter p\u00e5 ditt nettverk.",
-    "LabelBlastMessageInterval": "Levende meldinger invertall (sekunder)",
+    "LabelEnableBlastAliveMessagesHelp": "Sl\u00e5 p\u00e5 hvis serveren ikke regelmessig blir oppdaget av andre UPnP-enheter p\u00e5 ditt nettverk.",
+    "LabelBlastMessageInterval": "Intervall mellom keepalive meldinger (sekunder)",
     "LabelBlastMessageIntervalHelp": "Avgj\u00f8r tiden i sekunder mellom server levende meldinger.",
     "LabelDefaultUser": "Standard bruker:",
     "LabelDefaultUserHelp": "Avgj\u00f8r hvilket bruker bibliotek som skal bli vist p\u00e5 koblede enheter. Dette kan bli overskrevet for hver enhet som bruker profiler.",
     "TitleDlna": "DLNA",
     "TitleChannels": "Kanaler",
-    "HeaderServerSettings": "Server Innstillinger",
-    "LabelWeatherDisplayLocation": "V\u00e6r-visning lokalisering:",
+    "HeaderServerSettings": "Serverinnstillinger",
+    "LabelWeatherDisplayLocation": "Omr\u00e5de for v\u00e6rvisning:",
     "LabelWeatherDisplayLocationHelp": "US zip kode \/ By, Stat, Land \/ By, Land",
-    "LabelWeatherDisplayUnit": "V\u00e6r-visning enhet:",
+    "LabelWeatherDisplayUnit": "V\u00e6r-visning C eller F:",
     "OptionCelsius": "Celsius",
     "OptionFahrenheit": "Fahrenheit",
     "HeaderRequireManualLogin": "Krev manuell brukernavn oppf\u00f8ring for:",
-    "HeaderRequireManualLoginHelp": "N\u00e5r deaktiverte brukere kan  presentere en innloggingskjerm med ett visuelt utvalg av brukere.",
+    "HeaderRequireManualLoginHelp": "N\u00e5r deaktiverte kan brukere vises en innloggingskjerm med et visuelt utvalg av brukere.",
     "OptionOtherApps": "Andre applikasjoner",
     "OptionMobileApps": "Mobile applikasjoner",
-    "HeaderNotificationList": "Klikk p\u00e5 en varsling for \u00e5 konfigurere dens sending-alternativer.",
-    "NotificationOptionApplicationUpdateAvailable": "Applikasjon oppdatering tilgjengelig",
-    "NotificationOptionApplicationUpdateInstalled": "Applikasjon oppdatering installert",
-    "NotificationOptionPluginUpdateInstalled": "Programtillegg oppdatering installert",
+    "HeaderNotificationList": "Klikk p\u00e5 en varsling for \u00e5 konfigurere dennes sending-alternativer.",
+    "NotificationOptionApplicationUpdateAvailable": "Oppdatering tilgjengelig",
+    "NotificationOptionApplicationUpdateInstalled": "Oppdatering installert",
+    "NotificationOptionPluginUpdateInstalled": "Oppdatert programtillegg installert",
     "NotificationOptionPluginInstalled": "Programtillegg installert",
     "NotificationOptionPluginUninstalled": "Programtillegg er fjernet",
-    "NotificationOptionVideoPlayback": "Video avspilling startet",
-    "NotificationOptionAudioPlayback": "Lyd avspilling startet",
-    "NotificationOptionGamePlayback": "Spill avspilling startet",
-    "NotificationOptionVideoPlaybackStopped": "Video avspilling stoppet",
-    "NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet",
-    "NotificationOptionGamePlaybackStopped": "Spill avspilling stoppet",
-    "NotificationOptionTaskFailed": "Tidsplan oppgave feilet",
+    "NotificationOptionVideoPlayback": "Videoavspilling startet",
+    "NotificationOptionAudioPlayback": "Lydavspilling startet",
+    "NotificationOptionGamePlayback": "Spill startet",
+    "NotificationOptionVideoPlaybackStopped": "Videoavspilling stoppet",
+    "NotificationOptionAudioPlaybackStopped": "Lydavspilling stoppet",
+    "NotificationOptionGamePlaybackStopped": "Spill stoppet",
+    "NotificationOptionTaskFailed": "Planlagt oppgave feilet",
     "NotificationOptionInstallationFailed": "Installasjon feilet",
     "NotificationOptionNewLibraryContent": "Nytt innhold er lagt til",
     "NotificationOptionNewLibraryContentMultiple": "Nytt innhold lagt til (flere)",
-    "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "Som standard blir varslinger sent til dashbord innboksen. Bla igjennom programtillegg katalogen for \u00e5 installere valgfrie varslings-alternativer.",
-    "NotificationOptionServerRestartRequired": "Server omstart beh\u00f8ves",
+    "NotificationOptionCameraImageUploaded": "Bilde fra kamera lastet opp",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionServerRestartRequired": "Server m\u00e5 startes p\u00e5 nytt",
     "LabelNotificationEnabled": "Sl\u00e5 p\u00e5 denne varslingen",
     "LabelMonitorUsers": "Monitorer aktivitet fra:",
     "LabelSendNotificationToUsers": "Send varslingen til:",
@@ -679,7 +698,7 @@
     "CategoryPlugin": "Programtillegg",
     "LabelMessageTitle": "Meldingstittel:",
     "LabelAvailableTokens": "Tilgjengelige tokens:",
-    "AdditionalNotificationServices": "Bla gjennom programtillegg katalogen for \u00e5 installere valgfrie varslingstjenester.",
+    "AdditionalNotificationServices": "Bla gjennom katalogen over programtillegg for \u00e5 installere valgfrie varslingstjenester.",
     "OptionAllUsers": "Alle brukere:",
     "OptionAdminUsers": "Administratorer",
     "OptionCustomUsers": "Tilpasset",
@@ -689,7 +708,7 @@
     "ButtonArrowRight": "H\u00f8yre",
     "ButtonBack": "Tilbake",
     "ButtonInfo": "Info",
-    "ButtonOsd": "P\u00e5 skjermvisning",
+    "ButtonOsd": "Skjermmeldinger",
     "ButtonPageUp": "Side Opp",
     "ButtonPageDown": "Side Ned",
     "PageAbbreviation": "PG",
@@ -714,21 +733,21 @@
     "ButtonPause": "Pause",
     "ButtonNext": "Neste",
     "ButtonPrevious": "Forrige",
-    "LabelGroupMoviesIntoCollections": "Grupper filmer inni samlinger",
-    "LabelGroupMoviesIntoCollectionsHelp": "Ved visning av filmlister vil filmer som tilh\u00f8rer en samling vil bli vist som ett grupperende element.",
-    "NotificationOptionPluginError": "Programtillegg feil",
+    "LabelGroupMoviesIntoCollections": "Grupp\u00e9r filmer i samlinger",
+    "LabelGroupMoviesIntoCollectionsHelp": "Ved visning av filmlister vil filmer som tilh\u00f8rer en samling bli vist som ett gruppeelement.",
+    "NotificationOptionPluginError": "Programtillegg feilet",
     "ButtonVolumeUp": "Volum opp",
     "ButtonVolumeDown": "Volum ned",
     "ButtonMute": "Mute",
     "HeaderLatestMedia": "Siste Media",
     "OptionSpecialFeatures": "Spesielle Funksjoner",
     "HeaderCollections": "Samlinger",
-    "LabelProfileCodecsHelp": "Separert med komma. Dette feltet kan forbli tomt for \u00e5 gjelde alle kodeker.",
+    "LabelProfileCodecsHelp": "Separert med komma. Dette feltet kan forbli tomt for \u00e5 gjelde alle codecs.",
     "LabelProfileContainersHelp": "Separert med komma. Dette feltet kan forbli tomt for \u00e5 gjelde alle kontainere.",
-    "HeaderResponseProfile": "Respons Profil",
+    "HeaderResponseProfile": "Responsprofil",
     "LabelType": "Type:",
     "LabelPersonRole": "Rolle:",
-    "LabelPersonRoleHelp": "Rolle er generelt kun aktuelt for skuespillere.",
+    "LabelPersonRoleHelp": "Rolle er vanligvis kun tilgjengelig for skuespillere.",
     "LabelProfileContainer": "Kontainer:",
     "LabelProfileVideoCodecs": "Video kodek:",
     "LabelProfileAudioCodecs": "Lyd kodek:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Nedlastet innhold eldre enn dette vil bli slettet. Det vil v\u00e6re avspillbart via internett streaming.",
     "ChannelSettingsFormHelp": "Installer kanaler som eksempel Trailers og Vimeo i programtillegg katalogen.",
     "ButtonOptions": "Alternativer",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Filmer",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Spill",
@@ -982,23 +1002,23 @@
     "LabelLogs": "Logger:",
     "LabelMetadata": "Metadata:",
     "LabelImagesByName": "Bilder etter navn:",
-    "LabelTranscodingTemporaryFiles": "Transcoding midlertidige filer:",
+    "LabelTranscodingTemporaryFiles": "Transcoder midlertidige filer:",
     "HeaderLatestMusic": "Siste Musikk",
     "HeaderBranding": "Merke",
     "HeaderApiKeys": "Api N\u00f8kkler",
     "HeaderApiKeysHelp": "Eksterne programmer er p\u00e5lagt \u00e5 ha en API-n\u00f8kkel for \u00e5 kunne kommunisere med Media Browser. N\u00f8kkel f\u00e5es ved \u00e5 logge p\u00e5 med en Media Browser-konto, eller ved \u00e5 manuelt innvilge s\u00f8knaden en n\u00f8kkel.",
-    "HeaderApiKey": "Api N\u00f8kkel",
+    "HeaderApiKey": "API-n\u00f8kkel",
     "HeaderApp": "App",
     "HeaderDevice": "Enhet",
     "HeaderUser": "Bruker",
     "HeaderDateIssued": "Dato utstedt",
     "LabelChapterName": "Kapittel {0}",
     "HeaderNewApiKey": "Ny Api N\u00f8kkel",
-    "LabelAppName": "Applikasjon navn",
-    "LabelAppNameExample": "Eksempel: Sickbread, NzbDrone",
+    "LabelAppName": "Applikasjonsnavn",
+    "LabelAppNameExample": "Eksempel: Sickbeard, NzbDrone",
     "HeaderNewApiKeyHelp": "Innvilge en applikasjon tillatelser for \u00e5 kommunisere med Media Browser.",
     "HeaderHttpHeaders": "Http Headere",
-    "HeaderIdentificationHeader": "Identifiserings Header",
+    "HeaderIdentificationHeader": "Identifiseringsheader",
     "LabelValue": "Verdi:",
     "LabelMatchType": "Match type:",
     "OptionEquals": "Lik",
@@ -1013,7 +1033,7 @@
     "LabelView": "Se:",
     "TabUsers": "Brukere",
     "LabelSortName": "Sorterings navn:",
-    "LabelDateAdded": "Dato lagt til",
+    "LabelDateAdded": "Dato lagt til:",
     "HeaderFeatures": "Funksjoner",
     "HeaderAdvanced": "Avansert",
     "ButtonSync": "Synk",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Boks",
     "OptionBoxRear": "Boks bak",
     "OptionDisc": "Disk",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Meny",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "nedlasting av undertekster feilet for {0}",
     "LabelRunningTimeValue": "Spille tide: {0}",
     "LabelIpAddressValue": "Ip adresse: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "Bruker konfigurasjon har blitt oppdatert for {0}",
     "UserCreatedWithName": "Bruker {0} har blitt opprettet",
     "UserPasswordChangedWithName": "Passord har blitt endret for bruker {0}",
@@ -1101,7 +1123,7 @@
     "MessageApplicationUpdated": "Media Browser Server har blitt oppdatert",
     "AuthenticationSucceededWithUserName": "{0} autentisert med suksess",
     "FailedLoginAttemptWithUserName": "P\u00e5loggingsfors\u00f8k feilet fra {0}",
-    "UserDownloadingItemWithValues": "{0} is downloading {1}",
+    "UserDownloadingItemWithValues": "{0} laster ned {1}",
     "UserStartedPlayingItemWithValues": "{0} har startet avspilling av {1}",
     "UserStoppedPlayingItemWithValues": "{0} har stoppet avspilling av {1}",
     "AppDeviceValues": "App: {0} , Device: {1}",
@@ -1118,14 +1140,14 @@
     "LabelDisplayFoldersView": "Vis alle mapper som rene lagringsmapper",
     "ViewTypeLiveTvRecordingGroups": "Opptak",
     "ViewTypeLiveTvChannels": "Kanaler",
-    "LabelEasyPinCode": "Easy pin code:",
-    "EasyPasswordHelp": "Your easy pin code is used for offline access with supported Media Browser apps, and can also be used for easy in-network sign in.",
-    "LabelInNetworkSignInWithEasyPassword": "Enable in-network sign in with my easy pin code",
-    "LabelInNetworkSignInWithEasyPasswordHelp": "If enabled, you'll be able to use your easy pin code to sign in to Media Browser apps from inside your home network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.",
+    "LabelEasyPinCode": "Enkel PIN-kode:",
+    "EasyPasswordHelp": "Din enkle PIN-kode brukes for offline tilgang gjennom st\u00f8ttede Media Browser apps, og kan ogs\u00e5 brukes for enkel innlogging over nettverket.",
+    "LabelInNetworkSignInWithEasyPassword": "Tillat innlogging med PIN-kode via det lokale nettverket.",
+    "LabelInNetworkSignInWithEasyPasswordHelp": "Hvis denne aktiveres kan man bruke PIN-koden til \u00e5 logge inn i Media Browser apps via hjemmenettverket. Man trenger fremdeles det vanlige passordet for \u00e5 logge inn over internett. Hvis man ikke har valgt PIN-kode, vil man ikke trenge passord innen hjemmenettverket.",
     "HeaderPassword": "Passord",
     "HeaderLocalAccess": "Lokal Tilkobling",
     "HeaderViewOrder": "Visnings rekkef\u00f8lge",
-    "ButtonResetEasyPassword": "Reset easy pin code",
+    "ButtonResetEasyPassword": "Tilbakestill PIN-kode",
     "LabelSelectUserViewOrder": "Velg rekkef\u00f8lge dine visninger vil bli vist inn i Media Browser apps",
     "LabelMetadataRefreshMode": "Metadata oppfrisknings modus:",
     "LabelImageRefreshMode": "Bilde oppfrisknings modus:",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Hvis du \u00f8nsker \u00e5 fortsette, venligst bekreft med verdien av:",
     "ButtonIdentify": "Identifiser",
     "LabelAlbumArtist": "Album Artist",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Fellesskap anmeldelse:",
     "LabelVoteCount": "Stemme tall:",
@@ -1178,7 +1201,7 @@
     "LabelAirsAfterSeason": "Sendt etter sesong:",
     "LabelAirsBeforeEpisode": "Sendt f\u00f8r episode:",
     "LabelTreatImageAs": "Behandle bilde som:",
-    "LabelDisplayOrder": "Visnings rekkef\u00f8lge:",
+    "LabelDisplayOrder": "Visningsrekkef\u00f8lge:",
     "LabelDisplaySpecialsWithinSeasons": "Vis speialiteter innfor sensongen de ble sendt i",
     "HeaderCountries": "Land",
     "HeaderGenres": "Sjanger",
@@ -1188,7 +1211,7 @@
     "HeaderMetadataSettings": "Metadata innstilinger",
     "LabelLockItemToPreventChanges": "L\u00e5s dette elementet for \u00e5 hindre fremtidige endringer",
     "MessageLeaveEmptyToInherit": "La v\u00e6re blank for \u00e5 arve innstillinger fra et foreldre element, eller den globale standard verdien.",
-    "TabDonate": "Doner",
+    "TabDonate": "Don\u00e9r",
     "HeaderDonationType": "Donasjon type:",
     "OptionMakeOneTimeDonation": "Gi en egen donasjon",
     "OptionOneTimeDescription": "Dette er en ekstra donasjon til teamet for \u00e5 vise din st\u00f8tte. Det har ikke noen ekstra fordeler, og vil ikke produsere en supporter tasten.",
@@ -1199,7 +1222,7 @@
     "OptionNoThemeSong": "Ingen temasang",
     "OptionNoThemeVideo": "Ingen tema video",
     "LabelOneTimeDonationAmount": "Donasjons bel\u00f8p:",
-    "ButtonDonate": "Donate",
+    "ButtonDonate": "Don\u00e9r",
     "OptionActor": "Skuespiller",
     "OptionComposer": "Komponist",
     "OptionDirector": "Regiss\u00f8r",
@@ -1278,26 +1301,26 @@
     "TitleDevices": "Enheter",
     "TabCameraUpload": "Kameraopplasting",
     "TabDevices": "Enheter",
-    "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Media Browser.",
+    "HeaderCameraUploadHelp": "Last opp bilder og videoer tatt med mobiltelefonen din automatisk.",
     "MessageNoDevicesSupportCameraUpload": "Du har for \u00f8yeblikket ingen enheter som st\u00f8tter kameraopplasting.",
     "LabelCameraUploadPath": "Sti til kameraopplasting:",
-    "LabelCameraUploadPathHelp": "Select a custom upload path, if desired. If unspecified a default folder will be used. If using a custom path it will also need to be added in the library setup area.",
+    "LabelCameraUploadPathHelp": "Velg en tilpasset sti for opplasting dersom du \u00f8nsker det. Hvis intet er spesifiser vil standardmappen brukes. Hvis du bruker en tilpasset sti vil denne ogs\u00e5 m\u00e5tte legges til i innstillingene for bibliotek.",
     "LabelCreateCameraUploadSubfolder": "Lag en underkatalog for hver enhet",
-    "LabelCreateCameraUploadSubfolderHelp": "Specific folders can be assigned to a device by clicking on it from the Devices page.",
+    "LabelCreateCameraUploadSubfolderHelp": "Spesifikke mapper kan tildeles en enhet ved \u00e5 klikke p\u00e5 den fra Enhets-siden.",
     "LabelCustomDeviceDisplayName": "Visningsnavn:",
     "LabelCustomDeviceDisplayNameHelp": "Oppgi et egendefinert visningsnavn eller la det v\u00e6re tomt for \u00e5 bruke navnet som enheten rapporterer.",
     "HeaderInviteUser": "Invit\u00e9r Bruker",
     "LabelConnectGuestUserNameHelp": "Dette er brukernavnet som vennen din bruker for \u00e5 logge inn p\u00e5 Media Browser nettstedet, eller epostadressen deres.",
     "HeaderInviteUserHelp": "\u00c5 dele mediefiler med venner er enklere enn noen gang f\u00f8r med Media Browser Connect.",
     "ButtonSendInvitation": "Send Invitasjon",
-    "HeaderSignInWithConnect": "Sign in with Media Browser Connect",
+    "HeaderSignInWithConnect": "Logg inn med Media Browser Connect",
     "HeaderGuests": "Gjester",
     "HeaderLocalUsers": "Lokale Brukere",
     "HeaderPendingInvitations": "Ventende invitasjoner",
     "TabParentalControl": "Foreldrekontroll",
     "HeaderAccessSchedule": "Access Schedule",
     "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.",
-    "ButtonAddSchedule": "Add Schedule",
+    "ButtonAddSchedule": "Legg til timeplan",
     "LabelAccessDay": "Ukedag:",
     "LabelAccessStart": "Starttid:",
     "LabelAccessEnd": "Sluttid:",
@@ -1306,7 +1329,7 @@
     "OptionWeekdays": "Ukedager",
     "OptionWeekends": "Helger",
     "MessageProfileInfoSynced": "Brukerprofilinformasjon er synkronisert med Media Browser Connect.",
-    "HeaderOptionalLinkMediaBrowserAccount": "Optional: Link your Media Browser account",
+    "HeaderOptionalLinkMediaBrowserAccount": "Valgfritt: Link til din konto p\u00e5 Media Browser",
     "ButtonTrailerReel": "Trailer reel",
     "HeaderTrailerReel": "Trailer Reel",
     "OptionPlayUnwatchedTrailersOnly": "Play only unwatched trailers",
@@ -1314,7 +1337,7 @@
     "MessageNoTrailersFound": "No trailers found. Install the Trailer channel to enhance your movie experience by adding a library of internet trailers.",
     "HeaderNewUsers": "Nye Brukere",
     "ButtonSignUp": "Registrering",
-    "ButtonForgotPassword": "Forgot password",
+    "ButtonForgotPassword": "Glemt passord",
     "OptionDisableUserPreferences": "Deaktiver tillgang til bruker preferanser",
     "OptionDisableUserPreferencesHelp": "Hvis ativert, vil kun administratorer kunne konfigurere bruker profil bilder, passord og spr\u00e5k preferanser.",
     "HeaderSelectServer": "Velg Server",
@@ -1329,29 +1352,38 @@
     "HeaderShareMediaFolders": "Del media mapper",
     "MessageGuestSharingPermissionsHelp": "De fleste funksjonene er i utgangspunktet utilgjengelig for gjester, men kan aktiveres ved behov.",
     "HeaderInvitations": "Invitasjoner",
-    "LabelForgotPasswordUsernameHelp": "Enter your username, if you remember it.",
+    "LabelForgotPasswordUsernameHelp": "Skriv inn ditt brukernavn, hvis du husker det.",
     "HeaderForgotPassword": "Glemt passord",
     "TitleForgotPassword": "Glemt passord",
     "TitlePasswordReset": "Resett passord",
-    "LabelPasswordRecoveryPinCode": "Pin code:",
+    "LabelPasswordRecoveryPinCode": "PIN-kode:",
     "HeaderPasswordReset": "Resett passord",
-    "HeaderParentalRatings": "Parental Ratings",
-    "HeaderVideoTypes": "Video Types",
-    "HeaderYears": "Years",
-    "HeaderAddTag": "Add Tag",
-    "LabelBlockContentWithTags": "Block content with tags:",
+    "HeaderParentalRatings": "Foreldresensur",
+    "HeaderVideoTypes": "Videotyper",
+    "HeaderYears": "\u00c5r",
+    "HeaderAddTag": "Legg til tag",
+    "LabelBlockContentWithTags": "Blokker innhold med f\u00f8lgende tags:",
     "LabelTag": "Tag:",
-    "LabelEnableSingleImageInDidlLimit": "Limit to single embedded image",
-    "LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.",
-    "TabActivity": "Activity",
-    "TitleSync": "Sync",
-    "OptionAllowSyncContent": "Allow Sync",
-    "OptionAllowContentDownloading": "Allow media downloading",
-    "NameSeasonUnknown": "Season Unknown",
-    "NameSeasonNumber": "Season {0}",
-    "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)",
-    "TabJobs": "Jobs",
-    "TabSyncJobs": "Sync Jobs",
-    "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelEnableSingleImageInDidlLimit": "Maksimalt et innebygd bilde",
+    "LabelEnableSingleImageInDidlLimitHelp": "Noen enheter vil ikke vise bildene korrekt hvis flere bilder er innebygget i Didl.",
+    "TabActivity": "Aktivitet",
+    "TitleSync": "Synk",
+    "OptionAllowSyncContent": "Tillat synk",
+    "OptionAllowContentDownloading": "Tillat nedlasting av media",
+    "NameSeasonUnknown": "Ukjent sesong",
+    "NameSeasonNumber": "Sesong {0}",
+    "LabelNewUserNameHelp": "Brukernavn kan inneholder internasjonale bokstaver (a-z), tall (0-9), bindestrek (-), understrek (_), apostrof (') og punktum (.)",
+    "TabJobs": "Jobber",
+    "TabSyncJobs": "Synk-jobber",
+    "LabelTagFilterMode": "Modus",
+    "LabelTagFilterAllowModeHelp": "Hvis tillatte tagger brukes som del av mappestrukturen, vil innhold som er tagget kreve at foreldre-mappene ogs\u00e5 er tagget.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "Mer...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nl.json b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
index 213b61df21..05f5a06a2d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "Wanneer u de server draait vanaf de bron, geeft u het pad naar de map dashboard-ui op. Alle web client bestanden worden geladen vanaf deze locatie.",
     "ButtonConvertMedia": "Converteer media",
     "ButtonOrganize": "Organiseren",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pincode:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Annuleren",
+    "ButtonExit": "Afsluiten",
     "ButtonNew": "Nieuw",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paden",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Eenvoudige Pincode",
+    "HeaderGrownupsOnly": "Alleen voor volwassenen!",
+    "DividerOr": "-- of --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "Voor toegang toets uw pincode",
+    "KidsModeAdultInstruction": "Klik op het slotje in de rechterbenedenhoek om te configureren of blijf in de kindermodus. Uw pincode nodig zal zijn",
+    "ButtonConfigurePinCode": "Configureer pincode",
+    "HeaderAdultsReadHere": "Volwassenen Lees hier!",
     "RegisterWithPayPal": "Registreer met PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Vereist een Supporter lidmaatschap",
     "HeaderEnjoyDayTrial": "Geniet van een 14-daagse gratis proefversie",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "Indien ingeschakeld zullen bestanden met .rar en .zip extensies herkend worden als media bestanden.",
     "LabelEnterConnectUserName": "Gebruikersnaam of e-mail:",
     "LabelEnterConnectUserNameHelp": "Dit is uw Media Browser online account gebruikersnaam of wachtwoord.",
+    "LabelEnableEnhancedMovies": "Verbeterde film displays inschakelen",
+    "LabelEnableEnhancedMoviesHelp": "Wanneer ingeschakeld, zullen films worden weergegeven als mappen inclusief trailers, extra's, cast & crew en andere gerelateerde inhoud.",
     "HeaderSyncJobInfo": "Sync Opdrachten",
     "FolderTypeMixed": "Gemengde inhoud",
     "FolderTypeMovies": "Films",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Raadpleeg de mediabibliotheek wiki.",
     "LabelCountry": "Land:",
     "LabelLanguage": "Taal:",
+    "LabelTimeLimitHours": "Tijdslimiet (uren):",
     "ButtonJoinTheDevelopmentTeam": "Word lid van het Ontwikkel Team",
     "HeaderPreferredMetadataLanguage": "Gewenste metadata taal:",
     "LabelSaveLocalMetadata": "Sla afbeeldingen en metadata op in de mediamappen",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Geplande taken",
     "TabMyPlugins": "Mijn Plug-ins",
     "TabCatalog": "Catalogus",
-    "PluginsTitle": "Plug-ins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatische updates",
     "HeaderNowPlaying": "Wordt nu afgespeeld",
     "HeaderLatestAlbums": "Nieuwste Albums",
@@ -288,7 +307,7 @@
     "OptionAllowMediaPlayback": "Media afspelen toestaan",
     "OptionAllowBrowsingLiveTv": "Live TV toegang toestaan",
     "OptionAllowDeleteLibraryContent": "Media verwijderen toestaan",
-    "OptionAllowManageLiveTv": "Allow Live TV recording management",
+    "OptionAllowManageLiveTv": "Sta Live TV opname beheer toe",
     "OptionAllowRemoteControlOthers": "Op afstand besturen van andere gebruikers toestaan",
     "OptionAllowRemoteSharedDevices": "Op afstand besturen van gedeelde apparaten toestaan",
     "OptionAllowRemoteSharedDevicesHelp": "Dlna apparaten worden als gedeeld apparaat gezien totdat een gebruiker deze gaat gebruiken.",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Aantal dagen van de gids om te downloaden:",
     "LabelNumberOfGuideDaysHelp": "Het downloaden van meer dagen van de gids gegevens biedt de mogelijkheid verder vooruit te plannen en een beter overzicht geven, maar het zal ook langer duren om te downloaden. Auto kiest op basis van het aantal kanalen.",
-    "LabelActiveService": "Actieve Service:",
-    "LabelActiveServiceHelp": "Er kunnen meerdere tv Plug-ins worden ge\u00efnstalleerd, maar er kan er slechts een per keer actief zijn.",
     "OptionAutomatic": "Automatisch",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "Een Live TV service provider Plug-in is vereist om door te gaan.",
     "LiveTvPluginRequiredHelp": "Installeer a.u b een van onze beschikbare Plug-ins, zoals Next PVR of ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Aanpassen voor mediatype",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
     "NotificationOptionNewLibraryContentMultiple": "Nieuwe content toegevoegd (meerdere)",
     "NotificationOptionCameraImageUploaded": "Camera afbeelding ge\u00fcpload",
-    "SendNotificationHelp": "Meldingen worden geplaatst in de inbox op het dashboard. Blader door de Plug-in catalogus om aanvullende opties voor meldingen te installeren.",
+    "NotificationOptionUserLockedOut": "Gebruiker uitgesloten",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server herstart nodig",
     "LabelNotificationEnabled": "Deze melding inschakelen",
     "LabelMonitorUsers": "Monitor activiteit van:",
@@ -885,13 +904,13 @@
     "OptionCommunityMostWatchedSort": "Meest bekeken",
     "TabNextUp": "Volgend",
     "HeaderBecomeMediaBrowserSupporter": "Word een Media Browser Supporter",
-    "TextEnjoyBonusFeatures": "Enjoy Bonus Features",
+    "TextEnjoyBonusFeatures": "Geniet van Bonus Features",
     "MessageNoMovieSuggestionsAvailable": "Er zijn momenteel geen film suggesties beschikbaar. Begin met het bekijken en waardeer uw films, kom daarna terug om uw aanbevelingen te bekijken.",
     "MessageNoCollectionsAvailable": "Collecties maken het u mogelijk om Films, Series, Albums, Boeken en Games te groeperen. Klik op de + knop om Collecties aan te maken.",
     "MessageNoPlaylistsAvailable": "Met afspeellijsten kunt u een lijst maken waarvan de items achter elkaar afgespeeld worden. Om een item toe te voegen klikt u met rechts of tik en houd het vast om het te selecteren, klik vervolgens op Toevoegen aan afspeellijst.",
     "MessageNoPlaylistItemsAvailable": "De afspeellijst is momenteel leeg.",
     "ButtonDismiss": "Afwijzen",
-    "ButtonEditOtherUserPreferences": "Edit this user's profile, image and personal preferences.",
+    "ButtonEditOtherUserPreferences": "Wijzig het profiel, afbeelding en persoonlijke voorkeuren van deze gebruiker.",
     "LabelChannelStreamQuality": "Voorkeurs kwaliteit internet stream:",
     "LabelChannelStreamQualityHelp": "Bij weinig beschikbare bandbreedte kan het verminderen van de kwaliteit betere streams opleveren.",
     "OptionBestAvailableStreamQuality": "Best beschikbaar",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Gedownloade inhoud die ouder is zal worden verwijderd. Afspelen via internet streaming blijft mogelijk.",
     "ChannelSettingsFormHelp": "Installeer kanalen zoals Trailers en Vimeo in de Plug-in catalogus.",
     "ButtonOptions": "Opties",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Films",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -950,9 +970,9 @@
     "LabelProtocolInfo": "Protocol info:",
     "LabelProtocolInfoHelp": "De waarde die wordt gebruikt bij het reageren op GetProtocolInfo verzoeken van het apparaat.",
     "TabNfo": "Nfo",
-    "HeaderKodiMetadataHelp": "Media Browser includes native support for Nfo metadata files. To enable or disable Nfo metadata, use the Advanced tab to configure options for your media types.",
+    "HeaderKodiMetadataHelp": "Media Browser ondersteund NFO metadata bestanden. Gebruik het tabblad geavanceerd om het gebruik NFO metadata aan of uit te zetten.",
     "LabelKodiMetadataUser": "Synchroniseer gekeken informatie toe aan NFO's voor (gebruiker):",
-    "LabelKodiMetadataUserHelp": "Enable this to keep watch data in sync between Media Browser and Nfo files.",
+    "LabelKodiMetadataUserHelp": "Inschakelen om de bekijk gegevens tussen Media Browser en NFO bestanden te synchroniseren.",
     "LabelKodiMetadataDateFormat": "Uitgave datum formaat:",
     "LabelKodiMetadataDateFormatHelp": "Alle datums in NFO's zullen gelezen en geschreven worden met dit formaat.",
     "LabelKodiMetadataSaveImagePaths": "Bewaar afbeeldingspaden in NFO-bestanden",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Hoes",
     "OptionBoxRear": "Achterkant hoes",
     "OptionDisc": "Schijf",
+    "OptionIcon": "Pictogram",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Schermafbeelding",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Downloaden van ondertiteling voor {0} is mislukt",
     "LabelRunningTimeValue": "Looptijd: {0}",
     "LabelIpAddressValue": "IP adres: {0}",
+    "UserLockedOutWithName": "Gebruiker {0} is uitgesloten",
     "UserConfigurationUpdatedWithName": "Gebruikersinstellingen voor {0} zijn bijgewerkt",
     "UserCreatedWithName": "Gebruiker {0} is aangemaakt",
     "UserPasswordChangedWithName": "Wachtwoord voor {0} is gewijzigd",
@@ -1101,7 +1123,7 @@
     "MessageApplicationUpdated": "Media Browser Server is bijgewerkt",
     "AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
     "FailedLoginAttemptWithUserName": "Mislukte aanmeld poging van {0}",
-    "UserDownloadingItemWithValues": "{0} is downloading {1}",
+    "UserDownloadingItemWithValues": "{0} download {1}",
     "UserStartedPlayingItemWithValues": "{0} heeft afspelen van {1} gestart",
     "UserStoppedPlayingItemWithValues": "{0} heeft afspelen van {1} gestopt",
     "AppDeviceValues": "App: {0}, Apparaat: {1}",
@@ -1119,9 +1141,9 @@
     "ViewTypeLiveTvRecordingGroups": "Opnamen",
     "ViewTypeLiveTvChannels": "Kanalen",
     "LabelEasyPinCode": "Eenvoudige pincode:",
-    "EasyPasswordHelp": "Your easy pin code is used for offline access with supported Media Browser apps, and can also be used for easy in-network sign in.",
-    "LabelInNetworkSignInWithEasyPassword": "Enable in-network sign in with my easy pin code",
-    "LabelInNetworkSignInWithEasyPasswordHelp": "If enabled, you'll be able to use your easy pin code to sign in to Media Browser apps from inside your home network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.",
+    "EasyPasswordHelp": "Je easy pin code wordt gebruikt voor offline toegang met ondersteunende Media Browser apps en kan ook gebruikt worden voor eenvoudige aanmelding.",
+    "LabelInNetworkSignInWithEasyPassword": "Schakel eenvoudige lokale aanmelding in met mijn easy pin code",
+    "LabelInNetworkSignInWithEasyPasswordHelp": "Als dit ingeschakeld is is het mogelijk om lokaal met je easy pin code Media Browser apps aan te melden. Je gewone wachtwoord is alleen nodig bij toegang buitenshuis. Als de easy pin code leeg is kan je lokaal zonder wachtwoord aanmelden.",
     "HeaderPassword": "Wachtwoord",
     "HeaderLocalAccess": "Lokale toegang",
     "HeaderViewOrder": "Weergave volgorde",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Geef om door te gaan het resultaat in:",
     "ButtonIdentify": "Identificeer",
     "LabelAlbumArtist": "Album artiest:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Beoordeling gemeenschap:",
     "LabelVoteCount": "Aantal stemmen:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Opdrachten",
     "TabSyncJobs": "Sync Opdrachten",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "Als toegestane tags worden gebruikt in een diep geneste mappenstructuur, zal getagde inhoud vereisen dat de bovenliggende mappen ook getagd zijn.",
+    "HeaderThisUserIsCurrentlyDisabled": "Deze gebruiker is momenteel uitgesloten",
+    "MessageReenableUser": "Zie hieronder hoe opnieuw in te schakelen",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "Meer...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pl.json b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
index efb45a6592..037b188f3e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Anuluj",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Odnie\u015b si\u0119 do wiki biblioteki.",
     "LabelCountry": "Kraj:",
     "LabelLanguage": "J\u0119zyk:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferowany j\u0119zyk metadanych:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Zaplanowane zadania",
     "TabMyPlugins": "Moje wtyczki",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Wtyczki",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatyczne aktualizacje",
     "HeaderNowPlaying": "Teraz odtwarzany",
     "HeaderLatestAlbums": "Ostatnie albumy",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
index dc452f8466..88f91cc1e0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "Se executar o servidor a partir do c\u00f3digo, especifique o caminho para a pasta da interface do painel. Todos os arquivos do cliente web ser\u00e3o usados nesta localiza\u00e7\u00e3o.",
     "ButtonConvertMedia": "Converter m\u00eddia",
     "ButtonOrganize": "Organizar",
+    "LinkedToMediaBrowserConnect": "Conectado ao Media Browser Connect",
+    "HeaderSupporterBenefits": "Benef\u00edcios do Colaborador",
+    "HeaderAddUser": "Adicionar Usu\u00e1rio",
+    "LabelAddConnectSupporterHelp": "Para adicionar um usu\u00e1rio que n\u00e3o esteja listado, voc\u00ea precisar\u00e1 primeiro conectar sua conta ao Media Browser Connect a partir de sua p\u00e1gina de perfil de usu\u00e1rio.",
+    "LabelPinCode": "C\u00f3digo Pin:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancelar",
+    "ButtonExit": "Sair",
     "ButtonNew": "Novo",
     "HeaderTV": "TV",
     "HeaderAudio": "\u00c1udio",
     "HeaderVideo": "V\u00eddeo",
     "HeaderPaths": "Caminhos",
     "CategorySync": "Sincroniza\u00e7\u00e3o",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "C\u00f3digo de Pin Facil",
+    "HeaderGrownupsOnly": "Adultos Apenas!",
+    "DividerOr": "-- ou --",
+    "HeaderInstalledServices": "Servi\u00e7os Instalados",
+    "HeaderAvailableServices": "Servi\u00e7os Dispon\u00edveis",
+    "MessageNoServicesInstalled": "N\u00e3o existem servi\u00e7os instalados atualmente.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "Para acessar, por favor digite seu c\u00f3digo pin f\u00e1cil",
+    "KidsModeAdultInstruction": "Clique no \u00edcone de bloqueio no canto inferior direito para configurar ou deixar o modo infantil. Seu c\u00f3digo pin ser\u00e1 necess\u00e1rio.",
+    "ButtonConfigurePinCode": "Configurar c\u00f3digo pin",
+    "HeaderAdultsReadHere": "Adultos Leiam Aqui!",
     "RegisterWithPayPal": "Registrar com PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sincroniza\u00e7\u00e3o Necessita de uma Filia\u00e7\u00e3o de Colaborador",
     "HeaderEnjoyDayTrial": "Aproveite um per\u00edodo de 14 dias gr\u00e1tis para testes",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "Se ativado, arquivos com extens\u00f5es .rar e .zip ser\u00e3o detectados como arquivos de m\u00eddia.",
     "LabelEnterConnectUserName": "Nome de usu\u00e1rio ou email:",
     "LabelEnterConnectUserNameHelp": "Este \u00e9 o nome de usu\u00e1rio ou senha de sua conta online do Media Browser.",
+    "LabelEnableEnhancedMovies": "Ativar exibi\u00e7\u00f5es de filme avan\u00e7adas",
+    "LabelEnableEnhancedMoviesHelp": "Quando ativado, os filmes ser\u00e3o exibidos como pastas para incluir trailers, extras, elenco & equipe e outros conte\u00fados relacionados.",
     "HeaderSyncJobInfo": "Tarefa de Sincroniza\u00e7\u00e3o",
     "FolderTypeMixed": "Conte\u00fado misto",
     "FolderTypeMovies": "Filmes",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Consultar wiki da biblioteca de m\u00eddias",
     "LabelCountry": "Pa\u00eds:",
     "LabelLanguage": "Idioma:",
+    "LabelTimeLimitHours": "Limite de tempo (horas):",
     "ButtonJoinTheDevelopmentTeam": "Junte-se ao Time de Desenvolvimento",
     "HeaderPreferredMetadataLanguage": "Idioma preferido dos metadados:",
     "LabelSaveLocalMetadata": "Salvar artwork e metadados dentro das pastas da m\u00eddia",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Tarefas Agendadas",
     "TabMyPlugins": "Meus Plugins",
     "TabCatalog": "Cat\u00e1logo",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Atualiza\u00e7\u00f5es Autom\u00e1ticas",
     "HeaderNowPlaying": "Reproduzindo Agora",
     "HeaderLatestAlbums": "\u00c1lbuns Recentes",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "TV ao Vivo",
     "LabelNumberOfGuideDays": "N\u00famero de dias de dados do guia para download:",
     "LabelNumberOfGuideDaysHelp": "Fazer download de mais dias de dados do guia permite agendar com mais anteced\u00eancia e ver mais itens, mas tamb\u00e9m levar\u00e1 mais tempo para o download. Auto escolher\u00e1 com base no n\u00famero de canais.",
-    "LabelActiveService": "Servi\u00e7o Ativo:",
-    "LabelActiveServiceHelp": "V\u00e1rios plugins de tv podem ser instalados, mas apenas um pode estar ativo de cada vez.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Servi\u00e7os",
     "LiveTvPluginRequired": "Um provedor de servi\u00e7o de TV ao Vivo \u00e9 necess\u00e1rio para continuar.",
     "LiveTvPluginRequiredHelp": "Por favor, instale um de nossos plugins dispon\u00edveis como, por exemplo, Next Pvr ou ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Personalizar para o tipo de m\u00eddia:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Novo conte\u00fado adicionado",
     "NotificationOptionNewLibraryContentMultiple": "Novo conte\u00fado adicionado (m\u00faltiplo)",
     "NotificationOptionCameraImageUploaded": "Imagem da c\u00e2mera carregada",
-    "SendNotificationHelp": "Por padr\u00e3o, notifica\u00e7\u00f5es s\u00e3o entregues \u00e0 caixa de entrada do painel.  Explore o cat\u00e1logo de plugins para instalar op\u00e7\u00f5es adicionais de notifica\u00e7\u00f5es.",
+    "NotificationOptionUserLockedOut": "Usu\u00e1rio bloqueado",
+    "HeaderSendNotificationHelp": "Por padr\u00e3o, as notifica\u00e7\u00f5es s\u00e3o mostradas na caixa de entrada do painel. Explore o cat\u00e1logo dos plugins para instalar op\u00e7\u00f5es de notifica\u00e7\u00e3o adicionais.",
     "NotificationOptionServerRestartRequired": "Necessidade de reiniciar servidor",
     "LabelNotificationEnabled": "Ativar esta notifica\u00e7\u00e3o",
     "LabelMonitorUsers": "Monitorar atividade de:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "O conte\u00fado transferido que for mais velho que este valor ser\u00e1 exclu\u00eddo. Poder\u00e1 seguir reproduzindo-o atrav\u00e9s de streaming da internet.",
     "ChannelSettingsFormHelp": "Instalar canais como, por exemplo, Trailers e Vimeo no cat\u00e1logo de plugins.",
     "ButtonOptions": "Op\u00e7\u00f5es",
+    "ViewTypePlaylists": "Listas de Reprodu\u00e7\u00e3o",
     "ViewTypeMovies": "Filmes",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Jogos",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Caixa",
     "OptionBoxRear": "Traseira da Caixa",
     "OptionDisc": "Disco",
+    "OptionIcon": "\u00cdcone",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Imagem da tela",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Falha ao baixar legendas para {0}",
     "LabelRunningTimeValue": "Dura\u00e7\u00e3o: {0}",
     "LabelIpAddressValue": "Endere\u00e7o Ip: {0}",
+    "UserLockedOutWithName": "Usu\u00e1rio {0} foi bloqueado",
     "UserConfigurationUpdatedWithName": "A configura\u00e7\u00e3o do usu\u00e1rio {0} foi atualizada",
     "UserCreatedWithName": "O usu\u00e1rio {0} foi criado",
     "UserPasswordChangedWithName": "A senha do usu\u00e1rio {0} foi alterada",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Se desejar continuar, por favor confirme digitando o valor de:",
     "ButtonIdentify": "Identificar",
     "LabelAlbumArtist": "Artista do \u00e1lbum:",
+    "LabelAlbumArtists": "Artistas do \u00c1lbum:",
     "LabelAlbum": "\u00c1lbum:",
     "LabelCommunityRating": "Avalia\u00e7\u00e3o da comunidade:",
     "LabelVoteCount": "Contagem de votos:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Tarefas",
     "TabSyncJobs": "Tarefas de Sincroniza\u00e7\u00e3o",
     "LabelTagFilterMode": "Modo:",
-    "LabelTagFilterAllowModeHelp": "Se permitidas, as tags ser\u00e3o usadas como parte de uma estrutura de pastas agrupadas. Conte\u00fado com tags necessitar\u00e1 que as pastas superiores tamb\u00e9m tenham tags."
+    "LabelTagFilterAllowModeHelp": "Se permitidas, as tags ser\u00e3o usadas como parte de uma estrutura de pastas agrupadas. Conte\u00fado com tags necessitar\u00e1 que as pastas superiores tamb\u00e9m tenham tags.",
+    "HeaderThisUserIsCurrentlyDisabled": "Este usu\u00e1rio est\u00e1 desativado atualmente",
+    "MessageReenableUser": "Veja abaixo para reativar",
+    "LabelEnableInternetMetadataForTvPrograms": "Fazer download dos metadados da internet para:",
+    "OptionTVMovies": "Filmes da TV",
+    "HeaderUpcomingMovies": "Filmes Por Estrear",
+    "HeaderUpcomingPrograms": "Programas Por Estrear",
+    "ButtonMoreItems": "Mais...",
+    "LabelShowLibraryTileNames": "Mostrar os nomes das tiles da biblioteca",
+    "LabelShowLibraryTileNamesHelp": "Determina se os t\u00edtulos ser\u00e3o exibidos embaixo das tiles da biblioteca na p\u00e1gina in\u00edcio"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
index 8561b3a96d..1a9179143e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
@@ -44,19 +44,35 @@
     "OptionEnableWebClientResponseCache": "Enable web client response caching",
     "OptionDisableForDevelopmentHelp": "Configure these as needed for web client development purposes.",
     "OptionEnableWebClientResourceMinification": "Enable web client resource minification",
-    "LabelDashboardSourcePath": "Web client source path:",
-    "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
+    "LabelDashboardSourcePath": "Caminho da fonte do cliente web:",
+    "LabelDashboardSourcePathHelp": "Se correr o servidor a partir do c\u00f3digo fonte, especifique o caminho da pasta dashboard-ui. Todos os ficheiros do cliente web ser\u00e3o usados a partir desta localiza\u00e7\u00e3o.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancelar",
+    "ButtonExit": "Exit",
     "ButtonNew": "Novo",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Consulte a wiki",
     "LabelCountry": "Pa\u00eds:",
     "LabelLanguage": "Idioma:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Idioma preferido para metadados",
     "LabelSaveLocalMetadata": "Guardar imagens e metadados nas pastas multim\u00e9dia",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Tarefas Agendadas",
     "TabMyPlugins": "As minhas extens\u00f5es",
     "TabCatalog": "Cat\u00e1logo",
-    "PluginsTitle": "Extens\u00f5es",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Atualiza\u00e7\u00f5es autom\u00e1ticas",
     "HeaderNowPlaying": "A reproduzir",
     "HeaderLatestAlbums": "\u00daltimos \u00c1lbuns",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "TV ao Vivo",
     "LabelNumberOfGuideDays": "N\u00famero de dias de informa\u00e7\u00e3o do guia para transferir:",
     "LabelNumberOfGuideDaysHelp": "Transferir mais dias de informa\u00e7\u00e3o do guia permite agendar com maior anteced\u00eancia e ver mais listagens, no entanto ir\u00e1 levar mais tempo a transferir. Se optar que seja Autom\u00e1tico, ser\u00e1 escolhido baseado no n\u00famero de canais.",
-    "LabelActiveService": "Ativar Servi\u00e7o:",
-    "LabelActiveServiceHelp": "Podem ser instalados m\u00faltiplas extens\u00f5es para TV, mas s\u00f3 pode estar ativo um de cada vez.",
     "OptionAutomatic": "Autom\u00e1tico",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "Uma extens\u00e3o de um fornecedor de servi\u00e7o de TV ao Vivo \u00e9 necess\u00e1rio para continuar.",
     "LiveTvPluginRequiredHelp": "Por favor instale uma das nossas extens\u00f5es dispon\u00edveis, como a Next Pvr ou ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Personalizar para o tipo de conte\u00fado:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Adicionado novo conte\u00fado",
     "NotificationOptionNewLibraryContentMultiple": "Novo conte\u00fado adicionado (m\u00faltiplo)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "\u00c9 necess\u00e1rio reiniciar o servidor",
     "LabelNotificationEnabled": "Ativar esta notifica\u00e7\u00e3o",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -976,7 +996,7 @@
     "LabelAutomaticallyDonate": "Automatically donate this amount every month",
     "LabelAutomaticallyDonateHelp": "You can cancel at any time via your PayPal account.",
     "OptionList": "List",
-    "TabDashboard": "Dashboard",
+    "TabDashboard": "Painel Principal",
     "TitleServer": "Server",
     "LabelCache": "Cache:",
     "LabelLogs": "Logs:",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1321,7 +1344,7 @@
     "MessageNoServersAvailableToConnect": "No servers are available to connect to. If you've been invited to share a server, make sure to accept it below or by clicking the link in the email.",
     "TitleNewUser": "New User",
     "ButtonConfigurePassword": "Configure Password",
-    "HeaderDashboardUserPassword": "User passwords are managed within each user's personal profile settings.",
+    "HeaderDashboardUserPassword": "As senhas do utilizador s\u00e3o geridas dentro das prefer\u00eancias do seu perfil pessoal.",
     "HeaderLibraryAccess": "Library Access",
     "HeaderChannelAccess": "Channel Access",
     "HeaderLatestItems": "Latest Items",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ru.json b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
index 09ca235dfb..23f372184d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "\u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0445 \u043a\u043e\u0434\u043e\u0432, \u0443\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 dashboard-ui. \u0412\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f.",
     "ButtonConvertMedia": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0435",
     "ButtonOrganize": "\u0420\u0435\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c",
+    "LinkedToMediaBrowserConnect": "\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u044c \u0441 Media Browser Connect",
+    "HeaderSupporterBenefits": "\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430",
+    "HeaderAddUser": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f",
+    "LabelAddConnectSupporterHelp": "\u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u0442 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435, \u0432\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0435\u0433\u043e \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u043a Media Browser Connect \u0441 \u0435\u0433\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u044f.",
+    "LabelPinCode": "PIN-\u043a\u043e\u0434:",
     "ButtonOk": "\u041e\u041a",
     "ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
+    "ButtonExit": "\u0412\u044b\u0439\u0442\u0438",
     "ButtonNew": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c",
     "HeaderTV": "\u0422\u0412",
     "HeaderAudio": "\u0410\u0443\u0434\u0438\u043e",
     "HeaderVideo": "\u0412\u0438\u0434\u0435\u043e",
     "HeaderPaths": "\u041f\u0443\u0442\u0438",
     "CategorySync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f",
+    "TabPlaylist": "\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
     "HeaderEasyPinCode": "\u0423\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u044b\u0439 PIN-\u043a\u043e\u0434",
+    "HeaderGrownupsOnly": "\u0422\u043e\u043b\u044c\u043a\u043e \u0432\u0437\u0440\u043e\u0441\u043b\u044b\u0435!",
+    "DividerOr": "-- \u0438\u043b\u0438 --",
+    "HeaderInstalledServices": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u043b\u0443\u0436\u0431\u044b",
+    "HeaderAvailableServices": "\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043b\u0443\u0436\u0431\u044b",
+    "MessageNoServicesInstalled": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0436\u0431 \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
+    "HeaderToAccessPleaseEnterEasyPinCode": "\u0414\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448 \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u044b\u0439 PIN-\u043a\u043e\u0434",
+    "KidsModeAdultInstruction": "\u0429\u0451\u043b\u043a\u043d\u0438\u0442\u0435 \u043f\u043e \u0437\u043d\u0430\u0447\u043a\u0443 \u0437\u0430\u043c\u043a\u0430 \u0441\u043f\u0440\u0430\u0432\u0430 \u0432\u043d\u0438\u0437\u0443, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u043f\u043e\u043a\u0438\u043d\u0443\u0442\u044c \u0434\u0435\u0442\u0441\u043a\u0438\u0439 \u0440\u0435\u0436\u0438\u043c. \u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0430\u0448 PIN-\u043a\u043e\u0434.",
+    "ButtonConfigurePinCode": "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c PIN-\u043a\u043e\u0434",
+    "HeaderAdultsReadHere": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435, \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0437\u0434\u0435\u0441\u044c!",
     "RegisterWithPayPal": "\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 PayPal",
     "HeaderSyncRequiresSupporterMembership": "\u0414\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430",
     "HeaderEnjoyDayTrial": "\u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u043c 14-\u0434\u043d\u0435\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0431\u043d\u044b\u043c \u043f\u0435\u0440\u0438\u043e\u0434\u043e\u043c",
@@ -70,9 +86,11 @@
     "OptionDetectArchiveFilesAsMediaHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0444\u0430\u0439\u043b\u044b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438 .RAR \u0438 .ZIP \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043c\u0435\u0434\u0438\u0430\u0444\u0430\u0439\u043b\u044b.",
     "LabelEnterConnectUserName": "\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u043b\u0438 \u042d-\u043f\u043e\u0447\u0442\u0430",
     "LabelEnterConnectUserNameHelp": "\u042d\u0442\u043e - \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0432\u0430\u0448\u0435\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Media Browser.",
+    "LabelEnableEnhancedMovies": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0444\u0438\u043b\u044c\u043c\u043e\u0432",
+    "LabelEnableEnhancedMoviesHelp": "\u041f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0444\u0438\u043b\u044c\u043c\u044b \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043f\u0430\u043f\u043a\u0438, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b, \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b, \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u043e\u0432 \u0441\u044a\u0451\u043c\u043e\u043a \u0438 \u0434\u0440\u0443\u0433\u043e\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0435\u0435\u0441\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435.",
     "HeaderSyncJobInfo": "\u0417\u0430\u0434\u0430\u043d\u0438\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438",
     "FolderTypeMixed": "\u0420\u0430\u0437\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435",
-    "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u044b",
+    "FolderTypeMovies": "\u041a\u0438\u043d\u043e",
     "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430",
     "FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435 \u0432\u0438\u0434\u0435\u043e",
     "FolderTypePhotos": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0432\u0438\u043a\u0438 \u043f\u043e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435.",
     "LabelCountry": "\u0421\u0442\u0440\u0430\u043d\u0430:",
     "LabelLanguage": "\u042f\u0437\u044b\u043a:",
+    "LabelTimeLimitHours": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 (\u0447\u0430\u0441\u044b):",
     "ButtonJoinTheDevelopmentTeam": "\u0412\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432",
     "HeaderPreferredMetadataLanguage": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0439 \u044f\u0437\u044b\u043a \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445:",
     "LabelSaveLocalMetadata": "\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043d\u0443\u0442\u0440\u044c \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043e\u043a",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "\u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a",
     "TabMyPlugins": "\u041c\u043e\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u044b",
     "TabCatalog": "\u041a\u0430\u0442\u0430\u043b\u043e\u0433",
-    "PluginsTitle": "\u041f\u043b\u0430\u0433\u0438\u043d\u044b",
+    "TitlePlugins": "\u041f\u043b\u0430\u0433\u0438\u043d\u044b",
     "HeaderAutomaticUpdates": "\u0410\u0432\u0442\u043e\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f",
     "HeaderNowPlaying": " \u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e\u0435",
     "HeaderLatestAlbums": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0430\u043b\u044c\u0431\u043e\u043c\u044b",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u0422\u0412-\u044d\u0444\u0438\u0440",
     "LabelNumberOfGuideDays": "\u0427\u0438\u0441\u043b\u043e \u0434\u043d\u0435\u0439 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0433\u0438\u0434\u0430:",
     "LabelNumberOfGuideDaysHelp": "\u0427\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0434\u043d\u0435\u0439, \u0442\u0435\u043c \u0446\u0435\u043d\u043d\u0435\u0435 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0433\u0438\u0434\u0430, \u0434\u0430\u0432\u0430\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0440\u0430\u043d\u043d\u0435\u0433\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u043e\u0431\u044a\u0451\u043c\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0447, \u043d\u043e \u044d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0434\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0443. \u041f\u0440\u0438 \u0440\u0435\u0436\u0438\u043c\u0435 \u00ab\u0410\u0432\u0442\u043e\u00bb \u0432\u044b\u0431\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u0430\u043d\u0430\u043b\u043e\u0432.",
-    "LabelActiveService": "\u0410\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0441\u043b\u0443\u0436\u0431\u0430:",
-    "LabelActiveServiceHelp": "\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432 \u044d\u0444\u0438\u0440\u043d\u043e\u0433\u043e \u0442\u0432, \u043d\u043e \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445.",
     "OptionAutomatic": "\u0410\u0432\u0442\u043e",
+    "HeaderServices": "\u0421\u043b\u0443\u0436\u0431\u044b",
     "LiveTvPluginRequired": "\u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043b\u0430\u0433\u0438\u043d-\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0443\u0441\u043b\u0443\u0433 \u0422\u0412-\u044d\u0444\u0438\u0440\u0430.",
     "LiveTvPluginRequiredHelp": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043e\u0434\u0438\u043d \u0438\u0437 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, NextPVR \u0438\u043b\u0438 ServerWMC.",
     "LabelCustomizeOptionsPerMediaType": "\u041f\u043e\u0434\u0433\u043e\u043d\u043a\u0430 \u043f\u043e \u0442\u0438\u043f\u0443 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445:",
@@ -591,7 +609,7 @@
     "LabelDeleteLeftOverFiles": "\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f\u043c\u0438:",
     "LabelDeleteLeftOverFilesHelp": "\u0420\u0430\u0437\u0434\u0435\u043b\u044f\u0439\u0442\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u00ab;\u00bb. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: .nfo;.txt",
     "OptionOverwriteExistingEpisodes": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u044d\u043f\u0438\u0437\u043e\u0434\u044b",
-    "LabelTransferMethod": "\u041c\u0435\u0442\u043e\u0434 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0430",
+    "LabelTransferMethod": "\u041c\u0435\u0442\u043e\u0434 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430",
     "OptionCopy": "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435",
     "OptionMove": "\u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435",
     "LabelTransferMethodHelp": "\u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438\u0437 \u043f\u0430\u043f\u043a\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f",
@@ -613,11 +631,11 @@
     "MessagePleaseRestartServerToFinishUpdating": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0441\u0435\u0440\u0432\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439.",
     "LabelDownMixAudioScale": "\u041a\u043e\u043c\u043f\u0435\u043d\u0441\u0430\u0446\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u043d\u0438\u0436\u0430\u044e\u0449\u0435\u043c \u043c\u0438\u043a\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438:",
     "LabelDownMixAudioScaleHelp": "\u041a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0437\u0432\u0443\u043a\u0430 \u043f\u0440\u0438 \u043f\u043e\u043d\u0438\u0436\u0430\u044e\u0449\u0435\u043c \u043c\u0438\u043a\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438. \u0412\u0432\u0435\u0434\u0438\u0442\u0435 1, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u0432\u043d\u044f.",
-    "ButtonLinkKeys": "\u041f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043a\u043b\u044e\u0447",
+    "ButtonLinkKeys": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u043a\u043b\u044e\u0447\u0430",
     "LabelOldSupporterKey": "\u0421\u0442\u0430\u0440\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430",
     "LabelNewSupporterKey": "\u041d\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430",
-    "HeaderMultipleKeyLinking": "\u041f\u0435\u0440\u0435\u043d\u043e\u0441 \u043a \u043d\u043e\u0432\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443",
-    "MultipleKeyLinkingHelp": "\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u043e \u0441\u0442\u0430\u0440\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 \u043a \u043d\u043e\u0432\u043e\u043c\u0443.",
+    "HeaderMultipleKeyLinking": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u043a \u043d\u043e\u0432\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443",
+    "MultipleKeyLinkingHelp": "\u0415\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u043e\u0439, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0430 \u0441\u0442\u0430\u0440\u043e\u043c \u043a\u043b\u044e\u0447\u0435 \u043a \u043d\u043e\u0432\u043e\u043c\u0443.",
     "LabelCurrentEmailAddress": "\u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0430\u0434\u0440\u0435\u0441 \u042d-\u043f\u043e\u0447\u0442\u044b",
     "LabelCurrentEmailAddressHelp": "\u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0430\u0434\u0440\u0435\u0441 \u042d-\u043f\u043e\u0447\u0442\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447.",
     "HeaderForgotKey": "\u0417\u0430\u0431\u044b\u043b\u0438 \u043a\u043b\u044e\u0447?",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e",
     "NotificationOptionNewLibraryContentMultiple": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e (\u043c\u043d\u043e\u0433\u043e\u043a\u0440\u0430\u0442\u043d\u043e)",
     "NotificationOptionCameraImageUploaded": "\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f \u0441 \u043a\u0430\u043c\u0435\u0440\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430",
-    "SendNotificationHelp": "\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u044f\u0449\u0438\u043a \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0432 \u00ab\u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u0438\u00bb. \u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.",
+    "NotificationOptionUserLockedOut": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
+    "HeaderSendNotificationHelp": "\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0438\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u0438. \u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.",
     "NotificationOptionServerRestartRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0430",
     "LabelNotificationEnabled": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435",
     "LabelMonitorUsers": "\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043e\u0442:",
@@ -677,7 +696,7 @@
     "CategorySystem": "\u0421\u0438\u0441\u0442\u0435\u043c\u0430",
     "CategoryApplication": "\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435",
     "CategoryPlugin": "\u041f\u043b\u0430\u0433\u0438\u043d",
-    "LabelMessageTitle": "\u0422\u0435\u043a\u0441\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:",
+    "LabelMessageTitle": "\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:",
     "LabelAvailableTokens": "\u0418\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u044b:",
     "AdditionalNotificationServices": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.",
     "OptionAllUsers": "\u0412\u0441\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438",
@@ -704,7 +723,7 @@
     "TabNowPlaying": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u043e\u0435",
     "TabNavigation": "\u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044f",
     "TabControls": "\u0420\u0435\u0433\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0438",
-    "ButtonFullscreen": "\u0412\u043a\u043b\/\u0432\u044b\u043a\u043b \u043f\u043e\u043b\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d",
+    "ButtonFullscreen": "\u041f\u043e\u043b\u043d\u044b\u0439\/\u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d",
     "ButtonScenes": "\u041a \u0441\u0446\u0435\u043d\u0430\u043c",
     "ButtonSubtitles": "\u041a \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0430\u043c",
     "ButtonAudioTracks": "\u041a \u0430\u0443\u0434\u0438\u043e\u0434\u043e\u0440\u043e\u0436\u043a\u0430\u043c",
@@ -890,7 +909,7 @@
     "MessageNoCollectionsAvailable": "\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0442 \u0432\u0430\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u0438\u043b\u044c\u043c\u043e\u0432, \u0441\u0435\u0440\u0438\u0430\u043b\u043e\u0432, \u0430\u043b\u044c\u0431\u043e\u043c\u043e\u0432, \u043a\u043d\u0438\u0433 \u0438 \u0438\u0433\u0440. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 +, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439.",
     "MessageNoPlaylistsAvailable": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0438\u0437 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0440\u0430\u0437\u043e\u043c. \u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u043e \u0441\u043f\u0438\u0441\u043a\u0438, \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u0438\u043b\u0438 \u043a\u043e\u0441\u043d\u0438\u0442\u0435\u0441\u044c \u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0439\u0442\u0435, \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u00ab\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f\u00bb.",
     "MessageNoPlaylistItemsAvailable": "\u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u0443\u0441\u0442.",
-    "ButtonDismiss": "\u0421\u043a\u0440\u044b\u0442\u044c",
+    "ButtonDismiss": "\u041f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442\u044c",
     "ButtonEditOtherUserPreferences": "\u041f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0444\u0438\u043b\u044c, \u0440\u0438\u0441\u0443\u043d\u043e\u043a \u0438 \u043b\u0438\u0447\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.",
     "LabelChannelStreamQuality": "\u041f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438:",
     "LabelChannelStreamQualityHelp": "\u0412 \u0441\u0440\u0435\u0434\u0435 \u0441 \u043d\u0438\u0437\u043a\u043e\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u043d\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c\u044e, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043b\u044f \u043f\u043b\u0430\u0432\u043d\u043e\u0439 \u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438.",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u043e. \u041e\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u043c \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u0442\u0440\u0430\u043d\u0441\u043b\u044f\u0446\u0438\u0438.",
     "ChannelSettingsFormHelp": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u043a\u0430\u043d\u0430\u043b\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: Trailers \u0438\u043b\u0438 Vimeo) \u0438\u0437 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432.",
     "ButtonOptions": "\u041a \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c",
+    "ViewTypePlaylists": "\u0421\u043f\u0438\u0441\u043a\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
     "ViewTypeMovies": "\u041a\u0438\u043d\u043e",
     "ViewTypeTvShows": "\u0422\u0412",
     "ViewTypeGames": "\u0418\u0433\u0440\u044b",
@@ -981,7 +1001,7 @@
     "LabelCache": "\u041a\u0435\u0448:",
     "LabelLogs": "\u0416\u0443\u0440\u043d\u0430\u043b\u044b:",
     "LabelMetadata": "\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435:",
-    "LabelImagesByName": "\u0420\u0438\u0441\u0443\u043d\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u0438\u043c\u044f:",
+    "LabelImagesByName": "\u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0438\u0441\u0443\u043d\u043a\u0438:",
     "LabelTranscodingTemporaryFiles": "\u0412\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438:",
     "HeaderLatestMusic": "\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0438\u0437 \u043c\u0443\u0437\u044b\u043a\u0438",
     "HeaderBranding": "\u041e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u0435",
@@ -1048,6 +1068,7 @@
     "OptionBox": "\u041a\u043e\u0440\u043e\u0431\u043a\u0430",
     "OptionBoxRear": "\u041a\u043e\u0440\u043e\u0431\u043a\u0430 \u0441\u0437\u0430\u0434\u0438",
     "OptionDisc": "\u0414\u0438\u0441\u043a",
+    "OptionIcon": "\u0417\u043d\u0430\u0447\u043e\u043a",
     "OptionLogo": "\u041b\u043e\u0433\u043e\u0442\u0438\u043f",
     "OptionMenu": "\u041c\u0435\u043d\u044e",
     "OptionScreenshot": "\u0421\u043d\u0438\u043c\u043e\u043a \u044d\u043a\u0440\u0430\u043d\u0430",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044b \u043a {0} \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c",
     "LabelRunningTimeValue": "\u0412\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f: {0}",
     "LabelIpAddressValue": "IP-\u0430\u0434\u0440\u0435\u0441: {0}",
+    "UserLockedOutWithName": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c {0} \u0431\u044b\u043b \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
     "UserConfigurationUpdatedWithName": "\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437-\u043b\u044f {0} \u0431\u044b\u043b\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0430",
     "UserCreatedWithName": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c {0} \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d",
     "UserPasswordChangedWithName": "\u041f\u0430\u0440\u043e\u043b\u044c \u043f\u043e\u043b\u044c\u0437-\u043b\u044f {0} \u0431\u044b\u043b \u0438\u0437\u043c\u0435\u043d\u0451\u043d",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "\u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 \u044d\u0442\u043e, \u0432\u0432\u0435\u0434\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:",
     "ButtonIdentify": "\u0420\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0442\u044c",
     "LabelAlbumArtist": "\u0410\u043b\u044c\u0431\u043e\u043c\u043d\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c:",
+    "LabelAlbumArtists": "\u0410\u043b\u044c\u0431\u043e\u043c\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0438:",
     "LabelAlbum": "\u0410\u043b\u044c\u0431\u043e\u043c",
     "LabelCommunityRating": "\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430:",
     "LabelVoteCount": "\u041f\u043e\u0434\u0441\u0447\u0451\u0442 \u0433\u043e\u043b\u043e\u0441\u043e\u0432:",
@@ -1306,7 +1329,7 @@
     "OptionWeekdays": "\u0412 \u0431\u0443\u0434\u043d\u0438",
     "OptionWeekends": "\u0412 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435",
     "MessageProfileInfoSynced": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 Media Browser Connect.",
-    "HeaderOptionalLinkMediaBrowserAccount": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u0421\u0432\u044f\u0437\u0430\u0442\u044c \u0432\u0430\u0448\u0443 \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c Media Browser",
+    "HeaderOptionalLinkMediaBrowserAccount": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u0421\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0451\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 Media Browser",
     "ButtonTrailerReel": "\u0421\u043a\u043b\u0435\u0438\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b",
     "HeaderTrailerReel": "\u0421\u043a\u043b\u0435\u0439\u043a\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432",
     "OptionPlayUnwatchedTrailersOnly": "\u0412\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b",
@@ -1353,5 +1376,14 @@
     "TabJobs": "\u0417\u0430\u0434\u0430\u043d\u0438\u044f",
     "TabSyncJobs": "\u0417\u0430\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438",
     "LabelTagFilterMode": "\u0420\u0435\u0436\u0438\u043c:",
-    "LabelTagFilterAllowModeHelp": "\u0415\u0441\u043b\u0438 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0435 \u0442\u0435\u0433\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u043f\u043e\u043a, \u0442\u043e \u0434\u043b\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f, \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0433\u0430\u043c\u0438, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043f\u0430\u043f\u043a\u0438 \u0431\u044b\u043b\u0438 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u044b \u0442\u0430\u043a\u0436\u0435."
+    "LabelTagFilterAllowModeHelp": "\u0415\u0441\u043b\u0438 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0435 \u0442\u0435\u0433\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u043f\u043e\u043a, \u0442\u043e \u0434\u043b\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f, \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u0433\u0430\u043c\u0438, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043f\u0430\u043f\u043a\u0438 \u0431\u044b\u043b\u0438 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u044b \u0442\u0430\u043a\u0436\u0435.",
+    "HeaderThisUserIsCurrentlyDisabled": "\u042d\u0442\u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d",
+    "MessageReenableUser": "\u0421\u043c. \u043d\u0438\u0436\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0438",
+    "LabelEnableInternetMetadataForTvPrograms": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u043b\u044f:",
+    "OptionTVMovies": "\u0422\u0412 \u0444\u0438\u043b\u044c\u043c\u044b",
+    "HeaderUpcomingMovies": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0444\u0438\u043b\u044c\u043c\u044b",
+    "HeaderUpcomingPrograms": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438",
+    "ButtonMoreItems": "\u0415\u0449\u0451...",
+    "LabelShowLibraryTileNames": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438",
+    "LabelShowLibraryTileNamesHelp": "\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f, \u0431\u0443\u0434\u0443\u0442 \u043b\u0438 \u043d\u0430\u0434\u043f\u0438\u0441\u0438 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b \u043f\u043e\u0434 \u043f\u043b\u0438\u0442\u043a\u0430\u043c\u0438 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435."
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index dc80778da9..c2a115df45 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -401,9 +420,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -670,7 +688,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -912,6 +931,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1061,6 +1081,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1105,6 +1126,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1114,7 +1136,7 @@
     "MessageApplicationUpdated": "Media Browser Server has been updated",
     "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
     "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
-    "UserDownloadingItemWithValues":  "{0} is downloading {1}",
+    "UserDownloadingItemWithValues": "{0} is downloading {1}",
     "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
     "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
     "AppDeviceValues": "App: {0}, Device: {1}",
@@ -1156,6 +1178,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1369,5 +1392,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json b/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json
index 3b532deaea..575bbdc87f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/sl_SI.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Cancel",
+    "ButtonExit": "Exit",
     "ButtonNew": "New",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "Country:",
     "LabelLanguage": "Language:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "Plugins",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatic Updates",
     "HeaderNowPlaying": "Now Playing",
     "HeaderLatestAlbums": "Latest Albums",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/sv.json b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
index e6b233acda..045676a16e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "OK",
     "ButtonCancel": "Avbryt",
+    "ButtonExit": "Exit",
     "ButtonNew": "Nytillkommet",
     "HeaderTV": "TV",
     "HeaderAudio": "Ljud",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "Om aktiverad, kommer filer med .rar och .zip f\u00f6rl\u00e4ngningar att uppt\u00e4ckas som mediefiler.",
     "LabelEnterConnectUserName": "Anv\u00e4ndarnamn eller email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Synk jobb",
     "FolderTypeMixed": "Blandat inneh\u00e5ll",
     "FolderTypeMovies": "Filmer",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Se avsnittet om mediabibliotek i v\u00e5r Wiki.",
     "LabelCountry": "Land:",
     "LabelLanguage": "Spr\u00e5k:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "\u00d6nskat spr\u00e5k f\u00f6r metadata:",
     "LabelSaveLocalMetadata": "Spara grafik och metadata i mediamapparna",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Schemalagda aktiviteter",
     "TabMyPlugins": "Mina till\u00e4gg",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Till\u00e4gg",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Automatiska uppdateringar",
     "HeaderNowPlaying": "Nu spelas",
     "HeaderLatestAlbums": "Nytillkomna album",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live-TV",
     "LabelNumberOfGuideDays": "Antal dagars tabl\u00e5 att h\u00e4mta",
     "LabelNumberOfGuideDaysHelp": "H\u00e4mtning av en l\u00e4ngre periods tabl\u00e5 ger m\u00f6jlighet att boka inspelningar och se program l\u00e4ngre fram i tiden, men ger l\u00e4ngre nedladdningstid. \"Auto\" v\u00e4ljer baserat p\u00e5 antalet kanaler.",
-    "LabelActiveService": "Aktuell tj\u00e4nst:",
-    "LabelActiveServiceHelp": "Flera TV-till\u00e4gg kan vara installerade men bara en \u00e5t g\u00e5ngen kan vara aktiv.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "Du m\u00e5ste ha ett till\u00e4gg f\u00f6r live-TV installerad f\u00f6r att kunna forts\u00e4tta.",
     "LiveTvPluginRequiredHelp": "Installera ett av v\u00e5ra till\u00e4gg, t ex Next PVR eller ServerWMC.",
     "LabelCustomizeOptionsPerMediaType": "Anpassa f\u00f6r typ av media:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "Nytt inneh\u00e5ll har tillkommit",
     "NotificationOptionNewLibraryContentMultiple": "Nytillkommet inneh\u00e5ll finns (flera objekt)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "Meddelanden visas f\u00f6rvalt i kontrollpanelens inkorg. S\u00f6k efter fler meddelandetill\u00e4gg i till\u00e4ggskatalogen.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Servern m\u00e5ste startas om",
     "LabelNotificationEnabled": "Aktivera denna meddelandetyp",
     "LabelMonitorUsers": "\u00d6vervaka aktivitet fr\u00e5n:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Nedladdat inneh\u00e5ll \u00e4ldre \u00e4n s\u00e5 raderas. Det \u00e4r fortfarande tillg\u00e4ngligt via str\u00f6mning fr\u00e5n Internet.",
     "ChannelSettingsFormHelp": "Installera kanaler, t ex Trailers och Vimeo, via till\u00e4ggskatalogen.",
     "ButtonOptions": "Alternativ",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Filmer",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Spel",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box bakre",
     "OptionDisc": "Skiva",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logotyp",
     "OptionMenu": "Meny",
     "OptionScreenshot": "Sk\u00e4rmdump",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Nerladdning av undertexter f\u00f6r {0} misslyckades",
     "LabelRunningTimeValue": "Speltid: {0}",
     "LabelIpAddressValue": "IP-adress: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "Anv\u00e4ndarinst\u00e4llningarna f\u00f6r {0} har uppdaterats",
     "UserCreatedWithName": "Anv\u00e4ndaren {0} har skapats",
     "UserPasswordChangedWithName": "L\u00f6senordet f\u00f6r {0} har \u00e4ndrats",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "Om du vill forts\u00e4tta, ange v\u00e4rdet p\u00e5:",
     "ButtonIdentify": "Identifiera",
     "LabelAlbumArtist": "Albumartist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Anv\u00e4ndaromd\u00f6me:",
     "LabelVoteCount": "Antal r\u00f6ster:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Synkjobb",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "Mer...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/tr.json b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
index 18ab3fdd7d..1407eae9c3 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Tamam",
     "ButtonCancel": "\u0130ptal",
+    "ButtonExit": "Exit",
     "ButtonNew": "Yeni",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "\u00dclke",
     "LabelLanguage": "Dil",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Tercih edilen Meta Dili:",
     "LabelSaveLocalMetadata": "Medya meta dosyalar\u0131n\u0131 ayn\u0131 klas\u00f6rlere i\u015fle",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Zamanlanm\u0131\u015f G\u00f6revler",
     "TabMyPlugins": "Eklentilerim",
     "TabCatalog": "Katalog",
-    "PluginsTitle": "Eklentiler",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "Otomatik G\u00fcncelleme",
     "HeaderNowPlaying": "\u015eimdi \u00c7al\u0131n\u0131yor",
     "HeaderLatestAlbums": "Son Alb\u00fcmler",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Canl\u0131 TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Aktif Servis:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Otomatik",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Sunucu yeniden ba\u015flat\u0131lmal\u0131",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/uk.json b/MediaBrowser.Server.Implementations/Localization/Server/uk.json
index 448a0f8d61..f5863577a9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/uk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/uk.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438",
+    "ButtonExit": "Exit",
     "ButtonNew": "\u041d\u043e\u0432\u0438\u0439",
     "HeaderTV": "\u0422\u0411",
     "HeaderAudio": "\u0410\u0443\u0434\u0456\u043e",
     "HeaderVideo": "\u0412\u0456\u0434\u0435\u043e",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -64,15 +80,17 @@
     "LabelSyncTempPathHelp": "Specify a custom sync working folder. Converted media created during the sync process will be stored here.",
     "LabelCustomCertificatePath": "Custom certificate path:",
     "LabelCustomCertificatePathHelp": "Supply your own ssl certificate .pfx file. If omitted, the server will create a self-signed certificate.",
-    "TitleNotifications": "\u0421\u043f\u043e\u0432\u0456\u0449\u0435\u043d\u043d\u044f",
+    "TitleNotifications": "\u041f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f",
     "ButtonDonateWithPayPal": "Donate with PayPal",
     "OptionDetectArchiveFilesAsMedia": "Detect archive files as media",
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "\u0406\u043c\u2019\u044f \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430 \u0430\u0431\u043e email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
-    "FolderTypeMovies": "Movies",
+    "FolderTypeMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "FolderTypeMusic": "\u041c\u0443\u0437\u0438\u043a\u0430",
     "FolderTypeAdultVideos": "Adult videos",
     "FolderTypePhotos": "\u0421\u0432\u0456\u0442\u043b\u0438\u043d\u0438",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
     "LabelCountry": "\u041a\u0440\u0430\u0457\u043d\u0430:",
     "LabelLanguage": "\u041c\u043e\u0432\u0430:",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
     "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
@@ -170,7 +189,7 @@
     "HeaderResume": "Resume",
     "HeaderNextUp": "Next Up",
     "NoNextUpItemsMessage": "None found. Start watching your shows!",
-    "HeaderLatestEpisodes": "Latest Episodes",
+    "HeaderLatestEpisodes": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0435\u043f\u0456\u0437\u043e\u0434\u0438",
     "HeaderPersonTypes": "Person Types:",
     "TabSongs": "Songs",
     "TabAlbums": "Albums",
@@ -212,11 +231,11 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "My Plugins",
     "TabCatalog": "Catalog",
-    "PluginsTitle": "\u0414\u043e\u0434\u0430\u0442\u043a\u0438",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u0435 \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f",
     "HeaderNowPlaying": "Now Playing",
-    "HeaderLatestAlbums": "Latest Albums",
-    "HeaderLatestSongs": "Latest Songs",
+    "HeaderLatestAlbums": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0430\u043b\u044c\u0431\u043e\u043c\u0438",
+    "HeaderLatestSongs": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u043f\u0456\u0441\u043d\u0456",
     "HeaderRecentlyPlayed": "Recently Played",
     "HeaderFrequentlyPlayed": "Frequently Played",
     "DevBuildWarning": "Dev builds are the bleeding edge. Released often, these build have not been tested. The application may crash and entire features may not work at all.",
@@ -234,13 +253,13 @@
     "OptionHasTrailer": "Trailer",
     "OptionHasThemeSong": "Theme Song",
     "OptionHasThemeVideo": "Theme Video",
-    "TabMovies": "Movies",
-    "TabStudios": "Studios",
-    "TabTrailers": "Trailers",
+    "TabMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
+    "TabStudios": "\u0421\u0442\u0443\u0434\u0456\u0457",
+    "TabTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u0438",
     "LabelArtists": "Artists:",
     "LabelArtistsHelp": "Separate multiple using ;",
-    "HeaderLatestMovies": "Latest Movies",
-    "HeaderLatestTrailers": "Latest Trailers",
+    "HeaderLatestMovies": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0444\u0456\u043b\u044c\u043c\u0438",
+    "HeaderLatestTrailers": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u0438",
     "OptionHasSpecialFeatures": "Special Features",
     "OptionImdbRating": "IMDb Rating",
     "OptionParentalRating": "Parental Rating",
@@ -334,7 +353,7 @@
     "TabMusic": "Music",
     "TabOthers": "Others",
     "HeaderExtractChapterImagesFor": "Extract chapter images for:",
-    "OptionMovies": "Movies",
+    "OptionMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "OptionEpisodes": "Episodes",
     "OptionOtherVideos": "Other Videos",
     "TitleMetadata": "Metadata",
@@ -362,7 +381,7 @@
     "PasswordLocalhostMessage": "Passwords are not required when logging in from localhost.",
     "TabGuide": "Guide",
     "TabChannels": "Channels",
-    "TabCollections": "Collections",
+    "TabCollections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u0457",
     "HeaderChannels": "Channels",
     "TabRecordings": "Recordings",
     "TabScheduled": "Scheduled",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "Auto",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -438,7 +456,7 @@
     "LabelEveryXMinutes": "Every:",
     "HeaderTvTuners": "Tuners",
     "HeaderGallery": "Gallery",
-    "HeaderLatestGames": "Latest Games",
+    "HeaderLatestGames": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0456\u0433\u0440\u0438",
     "HeaderRecentlyPlayedGames": "Recently Played Games",
     "TabGameSystems": "Game Systems",
     "TitleMediaLibrary": "Media Library",
@@ -595,7 +613,7 @@
     "OptionCopy": "Copy",
     "OptionMove": "Move",
     "LabelTransferMethodHelp": "Copy or move files from the watch folder",
-    "HeaderLatestNews": "Latest News",
+    "HeaderLatestNews": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u043d\u043e\u0432\u0438\u043d\u0438",
     "HeaderHelpImproveMediaBrowser": "Help Improve Media Browser",
     "HeaderRunningTasks": "Running Tasks",
     "HeaderActiveDevices": "Active Devices",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -720,9 +739,9 @@
     "ButtonVolumeUp": "Volume up",
     "ButtonVolumeDown": "Volume down",
     "ButtonMute": "Mute",
-    "HeaderLatestMedia": "Latest Media",
+    "HeaderLatestMedia": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u043c\u0435\u0434\u0456\u0430",
     "OptionSpecialFeatures": "Special Features",
-    "HeaderCollections": "Collections",
+    "HeaderCollections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u0457",
     "LabelProfileCodecsHelp": "Separated by comma. This can be left empty to apply to all codecs.",
     "LabelProfileContainersHelp": "Separated by comma. This can be left empty to apply to all containers.",
     "HeaderResponseProfile": "Response Profile",
@@ -870,7 +889,7 @@
     "OptionMyViews": "My views",
     "OptionMyViewsSmall": "My views (small)",
     "OptionResumablemedia": "Resume",
-    "OptionLatestMedia": "Latest media",
+    "OptionLatestMedia": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u043c\u0435\u0434\u0456\u0430",
     "OptionLatestChannelMedia": "Latest channel items",
     "HeaderLatestChannelItems": "Latest Channel Items",
     "OptionNone": "None",
@@ -879,7 +898,7 @@
     "HeaderMetadataManager": "Metadata Manager",
     "HeaderPreferences": "Preferences",
     "MessageLoadingChannels": "Loading channel content...",
-    "MessageLoadingContent": "Loading content...",
+    "MessageLoadingContent": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0435\u043d\u043d\u044f \u0437\u043c\u0456\u0441\u0442\u0443...",
     "ButtonMarkRead": "Mark Read",
     "OptionDefaultSort": "Default",
     "OptionCommunityMostWatchedSort": "Most Watched",
@@ -903,17 +922,18 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
-    "ViewTypeMovies": "Movies",
+    "ViewTypePlaylists": "Playlists",
+    "ViewTypeMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
     "ViewTypeMusic": "Music",
     "ViewTypeMusicGenres": "Genres",
     "ViewTypeMusicArtists": "Artists",
-    "ViewTypeBoxSets": "Collections",
+    "ViewTypeBoxSets": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u0457",
     "ViewTypeChannels": "Channels",
     "ViewTypeLiveTV": "Live TV",
     "ViewTypeLiveTvNowPlaying": "Now Airing",
-    "ViewTypeLatestGames": "Latest Games",
+    "ViewTypeLatestGames": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0456\u0433\u0440\u0438",
     "ViewTypeRecentlyPlayedGames": "Recently Played",
     "ViewTypeGameFavorites": "Favorites",
     "ViewTypeGameSystems": "Game Systems",
@@ -927,11 +947,11 @@
     "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
     "ViewTypeMovieResume": "Resume",
     "ViewTypeMovieLatest": "Latest",
-    "ViewTypeMovieMovies": "Movies",
-    "ViewTypeMovieCollections": "Collections",
+    "ViewTypeMovieMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
+    "ViewTypeMovieCollections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u0457",
     "ViewTypeMovieFavorites": "Favorites",
     "ViewTypeMovieGenres": "Genres",
-    "ViewTypeMusicLatest": "Latest",
+    "ViewTypeMusicLatest": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456",
     "ViewTypeMusicAlbums": "Albums",
     "ViewTypeMusicAlbumArtists": "Album Artists",
     "HeaderOtherDisplaySettings": "Display Settings",
@@ -946,7 +966,7 @@
     "OptionDisplayAdultContent": "Display adult content",
     "OptionLibraryFolders": "Media folders",
     "TitleRemoteControl": "Remote Control",
-    "OptionLatestTvRecordings": "Latest recordings",
+    "OptionLatestTvRecordings": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456 \u0437\u0430\u043f\u0438\u0441\u0438",
     "LabelProtocolInfo": "Protocol info:",
     "LabelProtocolInfoHelp": "The value that will be used when responding to GetProtocolInfo requests from the device.",
     "TabNfo": "Nfo",
@@ -983,7 +1003,7 @@
     "LabelMetadata": "Metadata:",
     "LabelImagesByName": "Images by name:",
     "LabelTranscodingTemporaryFiles": "Transcoding temporary files:",
-    "HeaderLatestMusic": "Latest Music",
+    "HeaderLatestMusic": "\u041e\u0441\u0442\u0430\u043d\u043d\u044f \u043c\u0443\u0437\u0438\u043a\u0430",
     "HeaderBranding": "Branding",
     "HeaderApiKeys": "Api Keys",
     "HeaderApiKeysHelp": "External applications are required to have an Api key in order to communicate with Media Browser. Keys are issued by logging in with a Media Browser account, or by manually granting the application a key.",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1061,13 +1082,13 @@
     "OptionReportSongs": "Songs",
     "OptionReportSeries": "Series",
     "OptionReportSeasons": "Seasons",
-    "OptionReportTrailers": "Trailers",
+    "OptionReportTrailers": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u0438",
     "OptionReportMusicVideos": "Music videos",
-    "OptionReportMovies": "Movies",
+    "OptionReportMovies": "\u0424\u0456\u043b\u044c\u043c\u0438",
     "OptionReportHomeVideos": "Home videos",
     "OptionReportGames": "Games",
     "OptionReportEpisodes": "Episodes",
-    "OptionReportCollections": "Collections",
+    "OptionReportCollections": "\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u0457",
     "OptionReportBooks": "Books",
     "OptionReportArtists": "Artists",
     "OptionReportAlbums": "Albums",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1183,7 +1206,7 @@
     "HeaderCountries": "Countries",
     "HeaderGenres": "Genres",
     "HeaderPlotKeywords": "Plot Keywords",
-    "HeaderStudios": "Studios",
+    "HeaderStudios": "\u0421\u0442\u0443\u0434\u0456\u0457",
     "HeaderTags": "Tags",
     "HeaderMetadataSettings": "Metadata Settings",
     "LabelLockItemToPreventChanges": "Lock this item to prevent future changes",
@@ -1324,7 +1347,7 @@
     "HeaderDashboardUserPassword": "User passwords are managed within each user's personal profile settings.",
     "HeaderLibraryAccess": "Library Access",
     "HeaderChannelAccess": "Channel Access",
-    "HeaderLatestItems": "Latest Items",
+    "HeaderLatestItems": "\u041e\u0441\u0442\u0430\u043d\u043d\u0456",
     "LabelSelectLastestItemsFolders": "Include media from the following sections in Latest Items",
     "HeaderShareMediaFolders": "Share Media Folders",
     "MessageGuestSharingPermissionsHelp": "Most features are initially unavailable to guests but can be enabled as needed.",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/vi.json b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
index 016ebe72fb..00ef5b83ec 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "Ok",
     "ButtonCancel": "Tho\u00e1t",
+    "ButtonExit": "Exit",
     "ButtonNew": "M\u1edbi",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "Tham kh\u1ea3o th\u01b0 vi\u1ec7n wiki media.",
     "LabelCountry": "Qu\u1ed1c gia:",
     "LabelLanguage": "Ng\u00f4n ng\u1eef",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "Ng\u00f4n ng\u1eef metadata \u01b0a th\u00edch",
     "LabelSaveLocalMetadata": "L\u01b0u c\u00e1c \u1ea3nh ngh\u1ec7 thu\u1eadt v\u00e0 metadata v\u00e0o trong c\u00e1c th\u01b0 m\u1ee5c media",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "C\u00e1c plugin c\u1ee7a t\u00f4i",
     "TabCatalog": "Danh m\u1ee5c",
-    "PluginsTitle": "C\u00e1c plugin",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "T\u1ef1 \u0111\u1ed9ng c\u1eadp nh\u1eadt",
     "HeaderNowPlaying": "Ph\u00e1t ngay b\u00e2y gi\u1edd",
     "HeaderLatestAlbums": "C\u00e1c Album m\u1edbi nh\u1ea5t",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "Live TV",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "Active Service:",
-    "LabelActiveServiceHelp": "Multiple tv plugins can be installed but only one can be active at a time.",
     "OptionAutomatic": "T\u1ef1 \u0111\u1ed9ng",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "A Live TV service provider plugin is required in order to continue.",
     "LiveTvPluginRequiredHelp": "Please install one of our available plugins, such as Next Pvr or ServerWmc.",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
index da51d36010..ed4cd03f4e 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "\u5982\u679c\u4ece\u6e90\u8fd0\u884c\u670d\u52a1\u5668\uff0c\u8bf7\u6307\u5b9a\u63a7\u5236\u53f0UI\u6587\u4ef6\u5939\u8def\u5f84\u3002\u8fd9\u4e2a\u6587\u4ef6\u5939\u5c06\u63d0\u4f9bWeb\u5ba2\u6237\u7aef\u7684\u6240\u6709\u6587\u4ef6\u3002",
     "ButtonConvertMedia": "\u5a92\u4f53\u8f6c\u6362",
     "ButtonOrganize": "\u6574\u7406",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "\u786e\u5b9a",
     "ButtonCancel": "\u53d6\u6d88",
+    "ButtonExit": "Exit",
     "ButtonNew": "\u65b0\u589e",
     "HeaderTV": "\u7535\u89c6",
     "HeaderAudio": "\u97f3\u9891",
     "HeaderVideo": "\u89c6\u9891",
     "HeaderPaths": "\u8def\u5f84",
     "CategorySync": "\u540c\u6b65",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "\u7b80\u6613Pin\u7801",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "\u6ce8\u518cPayPal",
     "HeaderSyncRequiresSupporterMembership": "\u540c\u6b65\u9700\u8981\u652f\u6301\u8005\u4f1a\u5458",
     "HeaderEnjoyDayTrial": "\u4eab\u53d714\u5929\u514d\u8d39\u8bd5\u7528",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "\u5982\u679c\u542f\u7528\uff0c\u4e0e.RAR\u548c.zip\u6269\u5c55\u540d\u7684\u6587\u4ef6\u5c06\u88ab\u68c0\u6d4b\u4e3a\u5a92\u4f53\u6587\u4ef6\u3002",
     "LabelEnterConnectUserName": "\u7528\u6237\u540d\u6216\u7535\u5b50\u90ae\u4ef6\uff1a",
     "LabelEnterConnectUserNameHelp": "\u8fd9\u662f\u4f60\u7684Media Browser\u5728\u7ebf\u5e10\u6237\u7684\u7528\u6237\u540d\u6216\u5bc6\u7801\u3002",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "\u540c\u6b65\u4f5c\u4e1a",
     "FolderTypeMixed": "\u6df7\u5408\u5185\u5bb9",
     "FolderTypeMovies": "\u7535\u5f71",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u8bf7\u53c2\u9605\u5a92\u4f53\u5e93\u7ef4\u57fa\u3002",
     "LabelCountry": "\u56fd\u5bb6\uff1a",
     "LabelLanguage": "\u8bed\u8a00\uff1a",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "\u52a0\u5165\u5f00\u53d1\u56e2\u961f",
     "HeaderPreferredMetadataLanguage": "\u9996\u9009\u5a92\u4f53\u8d44\u6599\u8bed\u8a00\uff1a",
     "LabelSaveLocalMetadata": "\u4fdd\u5b58\u5a92\u4f53\u56fe\u50cf\u53ca\u8d44\u6599\u5230\u5a92\u4f53\u6240\u5728\u6587\u4ef6\u5939",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "\u8ba1\u5212\u4efb\u52a1",
     "TabMyPlugins": "\u6211\u7684\u63d2\u4ef6",
     "TabCatalog": "\u76ee\u5f55",
-    "PluginsTitle": "\u63d2\u4ef6",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "\u81ea\u52a8\u66f4\u65b0",
     "HeaderNowPlaying": "\u6b63\u5728\u64ad\u653e",
     "HeaderLatestAlbums": "\u6700\u65b0\u4e13\u8f91",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u7535\u89c6\u76f4\u64ad",
     "LabelNumberOfGuideDays": "\u4e0b\u8f7d\u51e0\u5929\u7684\u8282\u76ee\u6307\u5357\uff1a",
     "LabelNumberOfGuideDaysHelp": "\u4e0b\u8f7d\u66f4\u591a\u5929\u7684\u8282\u76ee\u6307\u5357\u53ef\u4ee5\u5e2e\u4f60\u8fdb\u4e00\u6b65\u67e5\u770b\u8282\u76ee\u5217\u8868\u5e76\u505a\u51fa\u63d0\u524d\u5b89\u6392\uff0c\u4f46\u4e0b\u8f7d\u8fc7\u7a0b\u4e5f\u5c06\u8017\u65f6\u66f4\u4e45\u3002\u5b83\u5c06\u57fa\u4e8e\u9891\u9053\u6570\u91cf\u81ea\u52a8\u9009\u62e9\u3002",
-    "LabelActiveService": "\u8fd0\u884c\u4e2d\u7684\u670d\u52a1\uff1a",
-    "LabelActiveServiceHelp": "\u591a\u4e2a\u7535\u89c6\u63d2\u4ef6\u53ef\u4ee5\u5b89\u88c5\uff0c\u4f46\u5728\u540c\u4e00\u65f6\u95f4\u53ea\u6709\u4e00\u4e2a\u53ef\u4ee5\u8fd0\u884c\u3002",
     "OptionAutomatic": "\u81ea\u52a8",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "\u8981\u7ee7\u7eed\u7684\u8bdd\u8bf7\u81f3\u5c11\u5b89\u88c5\u4e00\u4e2a\u7535\u89c6\u76f4\u64ad\u63d2\u4ef6\u3002",
     "LiveTvPluginRequiredHelp": "\u8bf7\u81f3\u5c11\u5b89\u88c5\u4e00\u4e2a\u6211\u4eec\u6240\u63d0\u4f9b\u7684\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1aNext Pvr \u6216\u8005 ServerWmc\u3002",
     "LabelCustomizeOptionsPerMediaType": "\u81ea\u5b9a\u4e49\u5a92\u4f53\u7c7b\u578b\uff1a",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "\u6dfb\u52a0\u65b0\u5185\u5bb9",
     "NotificationOptionNewLibraryContentMultiple": "\u65b0\u7684\u5185\u5bb9\u52a0\u5165\uff08\u591a\u4e2a\uff09",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u901a\u77e5\u88ab\u53d1\u9001\u5230\u63a7\u5236\u53f0\u7684\u6536\u4ef6\u7bb1\u3002\u6d4f\u89c8\u63d2\u4ef6\u76ee\u5f55\u53ef\u4ee5\u5b89\u88c5\u989d\u5916\u7684\u901a\u77e5\u9009\u9879\u3002",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "\u9700\u8981\u91cd\u65b0\u542f\u52a8\u670d\u52a1\u5668",
     "LabelNotificationEnabled": "\u542f\u7528\u6b64\u901a\u77e5",
     "LabelMonitorUsers": "\u76d1\u63a7\u6d3b\u52a8\uff1a",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "\u4e0b\u8f7d\u7684\u5185\u5bb9\u8d85\u8fc7\u6b64\u671f\u9650\u5c06\u88ab\u5220\u9664\u3002\u5b83\u4ecd\u53ef\u901a\u8fc7\u4e92\u8054\u7f51\u6d41\u5a92\u4f53\u64ad\u653e\u3002",
     "ChannelSettingsFormHelp": "\u5728\u63d2\u4ef6\u76ee\u5f55\u91cc\u5b89\u88c5\u9891\u9053\uff0c\u4f8b\u5982\uff1aTrailers \u548c Vimeo",
     "ButtonOptions": "\u9009\u9879",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "\u7535\u5f71",
     "ViewTypeTvShows": "\u7535\u89c6",
     "ViewTypeGames": "\u6e38\u620f",
@@ -1048,6 +1068,7 @@
     "OptionBox": "\u5305\u88c5\u76d2\u6b63\u9762\u56fe",
     "OptionBoxRear": "\u5305\u88c5\u76d2\u80cc\u9762\u56fe",
     "OptionDisc": "\u5149\u76d8",
+    "OptionIcon": "Icon",
     "OptionLogo": "\u6807\u5fd7",
     "OptionMenu": "\u83dc\u5355",
     "OptionScreenshot": "\u5c4f\u5e55\u622a\u56fe",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "\u4e3a {0} \u4e0b\u8f7d\u5b57\u5e55\u5931\u8d25",
     "LabelRunningTimeValue": "\u8fd0\u884c\u65f6\u95f4\uff1a {0}",
     "LabelIpAddressValue": "Ip \u5730\u5740\uff1a {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "\u7528\u6237\u914d\u7f6e\u5df2\u66f4\u65b0\u4e3a {0}",
     "UserCreatedWithName": "\u7528\u6237 {0} \u5df2\u88ab\u521b\u5efa",
     "UserPasswordChangedWithName": "\u5df2\u4e3a\u7528\u6237 {0} \u66f4\u6539\u5bc6\u7801",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "\u5982\u679c\u4f60\u60f3\u7ee7\u7eed\uff0c\u8bf7\u786e\u8ba4\u8f93\u5165\u7684\u503c\uff1a",
     "ButtonIdentify": "\u8bc6\u522b",
     "LabelAlbumArtist": "\u4e13\u8f91\u827a\u672f\u5bb6\uff1a",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "\u4e13\u8f91\uff1a",
     "LabelCommunityRating": "\u516c\u4f17\u8bc4\u5206\uff1a",
     "LabelVoteCount": "\u6295\u7968\u8ba1\u6570\uff1a",
@@ -1353,5 +1376,14 @@
     "TabJobs": "\u4f5c\u4e1a",
     "TabSyncJobs": "\u540c\u6b65\u4f5c\u4e1a",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "\u66f4\u591a...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
index 42a00b272f..5a0a37f0f4 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
@@ -48,15 +48,31 @@
     "LabelDashboardSourcePathHelp": "If running the server from source, specify the path to the dashboard-ui folder. All web client files will be served from this location.",
     "ButtonConvertMedia": "Convert media",
     "ButtonOrganize": "Organize",
+    "LinkedToMediaBrowserConnect": "Linked to Media Browser Connect",
+    "HeaderSupporterBenefits": "Supporter Benefits",
+    "HeaderAddUser": "Add User",
+    "LabelAddConnectSupporterHelp": "To add a user who isn't listed, you'll need to first link their account to Media Browser Connect from their user profile page.",
+    "LabelPinCode": "Pin code:",
     "ButtonOk": "OK",
     "ButtonCancel": "\u53d6\u6d88",
+    "ButtonExit": "Exit",
     "ButtonNew": "\u5275\u5efa",
     "HeaderTV": "TV",
     "HeaderAudio": "Audio",
     "HeaderVideo": "Video",
     "HeaderPaths": "Paths",
     "CategorySync": "Sync",
+    "TabPlaylist": "Playlist",
     "HeaderEasyPinCode": "Easy Pin Code",
+    "HeaderGrownupsOnly": "Grown-ups Only!",
+    "DividerOr": "-- or --",
+    "HeaderInstalledServices": "Installed Services",
+    "HeaderAvailableServices": "Available Services",
+    "MessageNoServicesInstalled": "No services are currently installed.",
+    "HeaderToAccessPleaseEnterEasyPinCode": "To access, please enter your easy pin code",
+    "KidsModeAdultInstruction": "Click the lock icon in the bottom right to configure or leave kids mode. Your pin code will be required.",
+    "ButtonConfigurePinCode": "Configure pin code",
+    "HeaderAdultsReadHere": "Adults Read Here!",
     "RegisterWithPayPal": "Register with PayPal",
     "HeaderSyncRequiresSupporterMembership": "Sync Requires a Supporter Membership",
     "HeaderEnjoyDayTrial": "Enjoy a 14 Day Free Trial",
@@ -70,6 +86,8 @@
     "OptionDetectArchiveFilesAsMediaHelp": "If enabled, files with .rar and .zip extensions will be detected as media files.",
     "LabelEnterConnectUserName": "User name or email:",
     "LabelEnterConnectUserNameHelp": "This is your Media Browser online account user name or password.",
+    "LabelEnableEnhancedMovies": "Enable enhanced movie displays",
+    "LabelEnableEnhancedMoviesHelp": "When enabled, movies will be displayed as folders to include trailers, extras, cast & crew, and other related content.",
     "HeaderSyncJobInfo": "Sync Job",
     "FolderTypeMixed": "Mixed content",
     "FolderTypeMovies": "Movies",
@@ -90,6 +108,7 @@
     "ReferToMediaLibraryWiki": "\u53c3\u7167\u5a92\u9ad4\u5eab\u7ef4\u57fa",
     "LabelCountry": "\u570b\u5bb6\uff1a",
     "LabelLanguage": "\u8a9e\u8a00\uff1a",
+    "LabelTimeLimitHours": "Time limit (hours):",
     "ButtonJoinTheDevelopmentTeam": "Join the Development Team",
     "HeaderPreferredMetadataLanguage": "\u9996\u9078\u5a92\u9ad4\u8cc7\u6599\u8a9e\u8a00\uff1a",
     "LabelSaveLocalMetadata": "\u4fdd\u5b58\u5a92\u9ad4\u5716\u50cf\u53ca\u8cc7\u6599\u5230\u5a92\u9ad4\u6a94\u6848\u6240\u5728\u7684\u6587\u4ef6\u593e",
@@ -212,7 +231,7 @@
     "ScheduledTasksTitle": "Scheduled Tasks",
     "TabMyPlugins": "\u6211\u7684\u63d2\u4ef6",
     "TabCatalog": "\u76ee\u9304",
-    "PluginsTitle": "\u63d2\u4ef6",
+    "TitlePlugins": "Plugins",
     "HeaderAutomaticUpdates": "\u81ea\u52d5\u66f4\u65b0",
     "HeaderNowPlaying": "\u6b63\u5728\u64ad\u653e",
     "HeaderLatestAlbums": "\u6700\u65b0\u5c08\u8f2f",
@@ -400,9 +419,8 @@
     "TitleLiveTV": "\u96fb\u8996\u529f\u80fd",
     "LabelNumberOfGuideDays": "Number of days of guide data to download:",
     "LabelNumberOfGuideDaysHelp": "Downloading more days worth of guide data provides the ability to schedule out further in advance and view more listings, but it will also take longer to download. Auto will choose based on the number of channels.",
-    "LabelActiveService": "\u904b\u884c\u4e2d\u7684\u670d\u52d9",
-    "LabelActiveServiceHelp": "\u53ef\u5b89\u88dd\u591a\u500b\u96fb\u8996\u529f\u80fd\u63d2\u4ef6\u53ef\uff0c\u4f46\u53ea\u6709\u4e00\u500b\u53ef\u4ee5\u5728\u540c\u4e00\u6642\u9593\u662f\u904b\u884c\u3002",
     "OptionAutomatic": "\u81ea\u52d5",
+    "HeaderServices": "Services",
     "LiveTvPluginRequired": "\u9700\u8981\u5b89\u88dd\u81f3\u5c11\u4e00\u500b\u96fb\u8996\u529f\u80fd\u63d2\u4ef6\u53bb\u7e7c\u7e8c",
     "LiveTvPluginRequiredHelp": "\u8acb\u5b89\u88dd\u4e00\u500b\u6211\u5011\u63d0\u4f9b\u7684\u63d2\u4ef6\uff0c\u5982Next PVR\u7684\u6216ServerWmc\u3002",
     "LabelCustomizeOptionsPerMediaType": "Customize for media type:",
@@ -667,7 +685,8 @@
     "NotificationOptionNewLibraryContent": "New content added",
     "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
     "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionUserLockedOut": "User locked out",
+    "HeaderSendNotificationHelp": "By default, notifications are delivered to your dashboard inbox. Browse the plugin catalog to install additional notification options.",
     "NotificationOptionServerRestartRequired": "Server restart required",
     "LabelNotificationEnabled": "Enable this notification",
     "LabelMonitorUsers": "Monitor activity from:",
@@ -903,6 +922,7 @@
     "LabelChannelDownloadAgeHelp": "Downloaded content older than this will be deleted. It will remain playable via internet streaming.",
     "ChannelSettingsFormHelp": "Install channels such as Trailers and Vimeo in the plugin catalog.",
     "ButtonOptions": "Options",
+    "ViewTypePlaylists": "Playlists",
     "ViewTypeMovies": "Movies",
     "ViewTypeTvShows": "TV",
     "ViewTypeGames": "Games",
@@ -1048,6 +1068,7 @@
     "OptionBox": "Box",
     "OptionBoxRear": "Box rear",
     "OptionDisc": "Disc",
+    "OptionIcon": "Icon",
     "OptionLogo": "Logo",
     "OptionMenu": "Menu",
     "OptionScreenshot": "Screenshot",
@@ -1092,6 +1113,7 @@
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelIpAddressValue": "Ip address: {0}",
+    "UserLockedOutWithName": "User {0} has been locked out",
     "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
     "UserCreatedWithName": "User {0} has been created",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
@@ -1143,6 +1165,7 @@
     "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
     "ButtonIdentify": "Identify",
     "LabelAlbumArtist": "Album artist:",
+    "LabelAlbumArtists": "Album artists:",
     "LabelAlbum": "Album:",
     "LabelCommunityRating": "Community rating:",
     "LabelVoteCount": "Vote count:",
@@ -1353,5 +1376,14 @@
     "TabJobs": "Jobs",
     "TabSyncJobs": "Sync Jobs",
     "LabelTagFilterMode": "Mode:",
-    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well."
+    "LabelTagFilterAllowModeHelp": "If allowed tags are used as part of a deeply nested folder structure, content that is tagged will require parent folders to be tagged as well.",
+    "HeaderThisUserIsCurrentlyDisabled": "This user is currently disabled",
+    "MessageReenableUser": "See below to reenable",
+    "LabelEnableInternetMetadataForTvPrograms": "Download internet metadata for:",
+    "OptionTVMovies": "TV Movies",
+    "HeaderUpcomingMovies": "Upcoming Movies",
+    "HeaderUpcomingPrograms": "Upcoming Programs",
+    "ButtonMoreItems": "More...",
+    "LabelShowLibraryTileNames": "Show library tile names",
+    "LabelShowLibraryTileNamesHelp": "Determines if labels will be displayed underneath library tiles on the home page"
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 1db1f8f5b4..3eb414068f 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -45,9 +45,9 @@
     <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Imazen.WebP, Version=0.2.0.0, Culture=neutral, processorArchitecture=MSIL">
+    <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\ThirdParty\libwebp\Imazen.WebP.dll</HintPath>
+      <HintPath>..\packages\ImageMagickSharp.1.0.0.11\lib\net45\ImageMagickSharp.dll</HintPath>
     </Reference>
     <Reference Include="MediaBrowser.Naming, Version=1.0.5509.27636, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
@@ -68,16 +68,15 @@
     <Reference Include="ServiceStack.Api.Swagger">
       <HintPath>..\ThirdParty\ServiceStack\ServiceStack.Api.Swagger.dll</HintPath>
     </Reference>
-    <Reference Include="SocketHttpListener, Version=1.0.5501.2204, Culture=neutral, processorArchitecture=MSIL">
+    <Reference Include="SocketHttpListener, Version=1.0.5554.26260, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SocketHttpListener.1.0.0.1\lib\net45\SocketHttpListener.dll</HintPath>
+      <HintPath>..\packages\SocketHttpListener.1.0.0.3\lib\net45\SocketHttpListener.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Data.SQLite">
       <HintPath>..\ThirdParty\System.Data.SQLite.ManagedOnly\1.0.94.0\System.Data.SQLite.dll</HintPath>
     </Reference>
-    <Reference Include="System.Drawing" />
     <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Data" />
     <Reference Include="System.Net" />
@@ -99,6 +98,9 @@
     <Reference Include="ServiceStack.Text">
       <HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
     </Reference>
+    <Reference Include="UniversalDetector">
+      <HintPath>..\ThirdParty\UniversalDetector\UniversalDetector.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="..\SharedVersion.cs">
@@ -126,7 +128,6 @@
     <Compile Include="Devices\DeviceManager.cs" />
     <Compile Include="Devices\DeviceRepository.cs" />
     <Compile Include="Devices\CameraUploadsFolder.cs" />
-    <Compile Include="Drawing\ImageExtensions.cs" />
     <Compile Include="Drawing\ImageHeader.cs" />
     <Compile Include="Drawing\PercentPlayedDrawer.cs" />
     <Compile Include="Drawing\PlayedIndicatorDrawer.cs" />
@@ -154,7 +155,6 @@
     <Compile Include="EntryPoints\UserDataChangeNotifier.cs" />
     <Compile Include="FileOrganization\OrganizerScheduledTask.cs" />
     <Compile Include="HttpServer\IHttpListener.cs" />
-    <Compile Include="HttpServer\NetListener\HttpListenerServer.cs" />
     <Compile Include="HttpServer\Security\AuthorizationContext.cs" />
     <Compile Include="HttpServer\ContainerAdapter.cs" />
     <Compile Include="HttpServer\GetSwaggerResource.cs" />
@@ -231,7 +231,9 @@
     <Compile Include="Localization\LocalizationManager.cs" />
     <Compile Include="Logging\PatternsLogger.cs" />
     <Compile Include="MediaEncoder\EncodingManager.cs" />
-    <Compile Include="Photos\DynamicImageProvider.cs" />
+    <Compile Include="Sync\SyncHelper.cs" />
+    <Compile Include="Sync\SyncJobOptions.cs" />
+    <Compile Include="UserViews\DynamicImageProvider.cs" />
     <Compile Include="News\NewsEntryPoint.cs" />
     <Compile Include="News\NewsService.cs" />
     <Compile Include="Notifications\CoreNotificationTypes.cs" />
@@ -248,6 +250,7 @@
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Photos\BaseDynamicImageProvider.cs" />
     <Compile Include="Photos\DynamicImageHelpers.cs" />
+    <Compile Include="UserViews\StripCollageBuilder.cs" />
     <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
     <Compile Include="Photos\PhotoAlbumImageProvider.cs" />
     <Compile Include="Playlists\PlaylistImageProvider.cs" />
@@ -280,6 +283,7 @@
     <Compile Include="Sorting\CommunityRatingComparer.cs" />
     <Compile Include="Sorting\CriticRatingComparer.cs" />
     <Compile Include="Sorting\DateCreatedComparer.cs" />
+    <Compile Include="Sorting\DateLastMediaAddedComparer.cs" />
     <Compile Include="Sorting\DatePlayedComparer.cs" />
     <Compile Include="Sorting\GameSystemComparer.cs" />
     <Compile Include="Sorting\IsFavoriteOrLikeComparer.cs" />
@@ -305,14 +309,19 @@
     <Compile Include="Sorting\StudioComparer.cs" />
     <Compile Include="Sorting\VideoBitRateComparer.cs" />
     <Compile Include="Sync\AppSyncProvider.cs" />
-    <Compile Include="Sync\CloudSyncProvider.cs" />
+    <Compile Include="Sync\CloudSyncProfile.cs" />
+    <Compile Include="Sync\IHasSyncQuality.cs" />
     <Compile Include="Sync\MediaSync.cs" />
+    <Compile Include="Sync\MultiProviderSync.cs" />
+    <Compile Include="Sync\ServerSyncScheduledTask.cs" />
+    <Compile Include="Sync\SyncedMediaSourceProvider.cs" />
     <Compile Include="Sync\SyncRegistrationInfo.cs" />
     <Compile Include="Sync\SyncConfig.cs" />
     <Compile Include="Sync\SyncJobProcessor.cs" />
     <Compile Include="Sync\SyncManager.cs" />
     <Compile Include="Sync\SyncRepository.cs" />
-    <Compile Include="Sync\SyncScheduledTask.cs" />
+    <Compile Include="Sync\SyncConvertScheduledTask.cs" />
+    <Compile Include="Sync\TargetDataProvider.cs" />
     <Compile Include="Themes\AppThemeManager.cs" />
     <Compile Include="TV\TVSeriesManager.cs" />
     <Compile Include="Udp\UdpMessageReceivedEventArgs.cs" />
@@ -420,6 +429,9 @@
     <EmbeddedResource Include="Localization\JavaScript\uk.json" />
     <EmbeddedResource Include="Localization\Server\bg_BG.json" />
     <EmbeddedResource Include="Localization\Server\uk.json" />
+    <EmbeddedResource Include="Drawing\fonts\webdings.ttf" />
+    <EmbeddedResource Include="Drawing\fonts\robotoregular.ttf" />
+    <EmbeddedResource Include="Drawing\fonts\MontserratLight.otf" />
     <None Include="Localization\JavaScript\sl_SI.json" />
     <EmbeddedResource Include="Localization\Server\sl_SI.json" />
     <None Include="packages.config" />
@@ -504,10 +516,20 @@
       <Link>swagger-ui\swagger-ui.min.js</Link>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <EmbeddedResource Include="UserViews\livetv\1.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\2.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\3.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\4.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\5.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\6.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\7.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\8.jpg" />
     <EmbeddedResource Include="Localization\iso6392.txt" />
     <EmbeddedResource Include="Localization\Ratings\be.txt" />
   </ItemGroup>
-  <ItemGroup />
+  <ItemGroup>
+    <Folder Include="HttpServer\NetListener\" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs b/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
index d8acbe06c8..a33fe21477 100644
--- a/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
+++ b/MediaBrowser.Server.Implementations/Notifications/CoreNotificationTypes.cs
@@ -143,6 +143,13 @@ namespace MediaBrowser.Server.Implementations.Notifications
                      Type = NotificationType.CameraImageUploaded.ToString(),
                      DefaultTitle = "A new camera image has been uploaded from {DeviceName}.",
                      Variables = new List<string>{"DeviceName"}
+                },
+
+                new NotificationTypeInfo
+                {
+                     Type = NotificationType.UserLockedOut.ToString(),
+                     DefaultTitle = "{UserName} has been locked out.",
+                     Variables = new List<string>{"UserName"}
                 }
             };
 
@@ -185,6 +192,10 @@ namespace MediaBrowser.Server.Implementations.Notifications
             {
                 note.Category = _localization.GetLocalizedString("CategorySync");
             }
+            else if (note.Type.IndexOf("UserLockedOut", StringComparison.OrdinalIgnoreCase) != -1)
+            {
+                note.Category = _localization.GetLocalizedString("CategoryUser");
+            }
             else
             {
                 note.Category = _localization.GetLocalizedString("CategorySystem");
diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
index d67c1894d8..f8cb6c9f4a 100644
--- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
+++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Logging;
+using System.Text;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using System;
 using System.Data;
@@ -173,5 +174,36 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 return stream.ToArray();
             }
         }
+
+        public static void AddColumn(this IDbConnection connection, ILogger logger, string table, string columnName, string type)
+        {
+            using (var cmd = connection.CreateCommand())
+            {
+                cmd.CommandText = "PRAGMA table_info(" + table + ")";
+
+                using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+                {
+                    while (reader.Read())
+                    {
+                        if (!reader.IsDBNull(1))
+                        {
+                            var name = reader.GetString(1);
+
+                            if (string.Equals(name, columnName, StringComparison.OrdinalIgnoreCase))
+                            {
+                                return;
+                            }
+                        }
+                    }
+                }
+            }
+
+            var builder = new StringBuilder();
+
+            builder.AppendLine("alter table " + table);
+            builder.AppendLine("add column " + columnName + " " + type);
+
+            connection.RunQueries(new[] { builder.ToString() }, logger);
+        }
     }
 }
\ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
index 369e8512fa..4ff42c1fda 100644
--- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs
@@ -1,8 +1,10 @@
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using System;
 using System.Collections.Generic;
@@ -14,18 +16,34 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Photos
 {
-    public abstract class BaseDynamicImageProvider<T> : IHasChangeMonitor, IForcedProvider
-        where T : IHasImages
+    public abstract class BaseDynamicImageProvider<T> : IHasChangeMonitor, IForcedProvider, ICustomMetadataProvider<T>, IHasOrder
+        where T : IHasMetadata
     {
         protected IFileSystem FileSystem { get; private set; }
         protected IProviderManager ProviderManager { get; private set; }
+        protected IApplicationPaths ApplicationPaths { get; private set; }
 
-        protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager)
+        protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths)
         {
+            ApplicationPaths = applicationPaths;
             ProviderManager = providerManager;
             FileSystem = fileSystem;
         }
 
+        public virtual bool Supports(IHasImages item)
+        {
+            return true;
+        }
+
+        public virtual IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+        {
+            return new List<ImageType>
+            {
+                ImageType.Primary,
+                ImageType.Thumb
+            };
+        }
+
         public async Task<ItemUpdateType> FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
             if (!Supports(item))
@@ -39,37 +57,23 @@ namespace MediaBrowser.Server.Implementations.Photos
             return primaryResult | thumbResult;
         }
 
-        protected virtual bool Supports(IHasImages item)
-        {
-            return true;
-        }
-
-        protected abstract Task<List<BaseItem>> GetItemsWithImages(IHasImages item);
-
-        private const string Version = "3";
-        protected  string GetConfigurationCacheKey(List<BaseItem> items)
-        {
-            return (Version + "_" + string.Join(",", items.Select(i => i.Id.ToString("N")).ToArray())).GetMD5().ToString("N");
-        }
-
         protected async Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
             var items = await GetItemsWithImages(item).ConfigureAwait(false);
-            var cacheKey = GetConfigurationCacheKey(items);
+            var cacheKey = GetConfigurationCacheKey(items, item.Name);
 
             if (!HasChanged(item, imageType, cacheKey))
             {
                 return ItemUpdateType.None;
             }
 
-            return await FetchAsyncInternal(item, items, imageType, cacheKey, options, cancellationToken).ConfigureAwait(false);
+            return await FetchToFileInternal(item, items, imageType, cacheKey, cancellationToken).ConfigureAwait(false);
         }
 
-        protected async Task<ItemUpdateType> FetchAsyncInternal(IHasImages item, 
+        protected async Task<ItemUpdateType> FetchToFileInternal(IHasImages item,
             List<BaseItem> itemsWithImages,
-            ImageType imageType, 
-            string cacheKey, 
-            MetadataRefreshOptions options, 
+            ImageType imageType,
+            string cacheKey,
             CancellationToken cancellationToken)
         {
             var stream = await CreateImageAsync(item, itemsWithImages, imageType, 0).ConfigureAwait(false);
@@ -103,19 +107,54 @@ namespace MediaBrowser.Server.Implementations.Photos
             return ItemUpdateType.ImageUpdate;
         }
 
+        public async Task<DynamicImageResponse> GetImage(IHasImages item, ImageType type, CancellationToken cancellationToken)
+        {
+            var items = await GetItemsWithImages(item).ConfigureAwait(false);
+            var cacheKey = GetConfigurationCacheKey(items, item.Name);
+
+            var result = await CreateImageAsync(item, items, type, 0).ConfigureAwait(false);
+
+            return new DynamicImageResponse
+            {
+                HasImage = result != null,
+                Stream = result,
+                InternalCacheKey = cacheKey,
+                Format = ImageFormat.Png
+            };
+        }
+
+        protected abstract Task<List<BaseItem>> GetItemsWithImages(IHasImages item);
+
+        private const string Version = "3";
+        protected string GetConfigurationCacheKey(List<BaseItem> items, string itemName)
+        {
+            return (Version + "_" + (itemName ?? string.Empty) + "_" + string.Join(",", items.Select(i => i.Id.ToString("N")).ToArray())).GetMD5().ToString("N");
+        }
+
         protected Task<Stream> GetThumbCollage(List<BaseItem> items)
         {
-            return DynamicImageHelpers.GetThumbCollage(items.Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb)).ToList(),
+            var files = items
+                .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
+                .Where(i => !string.IsNullOrWhiteSpace(i))
+                .ToList();
+
+            return DynamicImageHelpers.GetThumbCollage(files,
                 FileSystem,
                 1600,
-                900);
+                900,
+                ApplicationPaths);
         }
 
         protected Task<Stream> GetSquareCollage(List<BaseItem> items)
         {
-            return DynamicImageHelpers.GetSquareCollage(items.Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb)).ToList(),
+            var files = items
+                .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
+                .Where(i => !string.IsNullOrWhiteSpace(i))
+                .ToList();
+
+            return DynamicImageHelpers.GetSquareCollage(files,
                 FileSystem,
-                800);
+                800, ApplicationPaths);
         }
 
         public string Name
@@ -123,9 +162,9 @@ namespace MediaBrowser.Server.Implementations.Photos
             get { return "Dynamic Image Provider"; }
         }
 
-        public async Task<Stream> CreateImageAsync(IHasImages item, 
+        protected virtual async Task<Stream> CreateImageAsync(IHasImages item,
             List<BaseItem> itemsWithImages,
-            ImageType imageType, 
+            ImageType imageType,
             int imageIndex)
         {
             if (itemsWithImages.Count == 0)
@@ -146,7 +185,7 @@ namespace MediaBrowser.Server.Implementations.Photos
             }
 
             var items = GetItemsWithImages(item).Result;
-            var cacheKey = GetConfigurationCacheKey(items);
+            var cacheKey = GetConfigurationCacheKey(items, item.Name);
 
             return HasChanged(item, ImageType.Primary, cacheKey) || HasChanged(item, ImageType.Thumb, cacheKey);
         }
@@ -174,13 +213,19 @@ namespace MediaBrowser.Server.Implementations.Photos
         }
 
         protected List<BaseItem> GetFinalItems(List<BaseItem> items)
+        {
+            // Rotate the images no more than once per week
+            return GetFinalItems(items, 4);
+        }
+
+        protected virtual List<BaseItem> GetFinalItems(List<BaseItem> items, int limit)
         {
             // Rotate the images no more than once per week
             var random = new Random(GetWeekOfYear()).Next();
 
             return items
                 .OrderBy(i => random - items.IndexOf(i))
-                .Take(4)
+                .Take(limit)
                 .OrderBy(i => i.Name)
                 .ToList();
         }
@@ -195,5 +240,14 @@ namespace MediaBrowser.Server.Implementations.Photos
 
             return weekNo;
         }
+
+        public int Order
+        {
+            get
+            {
+                // Run before the default image provider which will download placeholders
+                return 0;
+            }
+        }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs b/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs
index 1099bd1709..7f84350972 100644
--- a/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs
+++ b/MediaBrowser.Server.Implementations/Photos/DynamicImageHelpers.cs
@@ -1,9 +1,10 @@
-using MediaBrowser.Common.IO;
+using ImageMagickSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using System;
 using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
 using System.IO;
+using System.Linq;
 using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Photos
@@ -13,8 +14,18 @@ namespace MediaBrowser.Server.Implementations.Photos
         public static async Task<Stream> GetThumbCollage(List<string> files,
             IFileSystem fileSystem,
             int width,
-            int height)
+            int height, IApplicationPaths appPaths)
         {
+            if (files.Any(string.IsNullOrWhiteSpace))
+            {
+                throw new ArgumentException("Empty file found in files list");
+            }
+
+            if (files.Count == 0)
+            {
+                return null;
+            }
+
             if (files.Count < 3)
             {
                 return await GetSingleImage(files, fileSystem).ConfigureAwait(false);
@@ -27,16 +38,8 @@ namespace MediaBrowser.Server.Implementations.Photos
             int cellHeight = height;
             var index = 0;
 
-            var img = new Bitmap(width, height, PixelFormat.Format32bppPArgb);
-
-            using (var graphics = Graphics.FromImage(img))
+            using (var wand = new MagickWand(width, height, new PixelWand(ColorName.None, 1)))
             {
-                graphics.CompositingQuality = CompositingQuality.HighQuality;
-                graphics.SmoothingMode = SmoothingMode.HighQuality;
-                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
-                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
-                graphics.CompositingMode = CompositingMode.SourceCopy;
-
                 for (var row = 0; row < rows; row++)
                 {
                     for (var col = 0; col < cols; col++)
@@ -46,34 +49,35 @@ namespace MediaBrowser.Server.Implementations.Photos
 
                         if (files.Count > index)
                         {
-                            using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+                            using (var innerWand = new MagickWand(files[index]))
                             {
-                                using (var memoryStream = new MemoryStream())
-                                {
-                                    await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
-                                    memoryStream.Position = 0;
-
-                                    using (var imgtemp = Image.FromStream(memoryStream, true, false))
-                                    {
-                                        graphics.DrawImage(imgtemp, x, y, cellWidth, cellHeight);
-                                    }
-                                }
+                                innerWand.CurrentImage.ResizeImage(cellWidth, cellHeight);
+                                wand.CurrentImage.CompositeImage(innerWand, CompositeOperator.OverCompositeOp, x, y);
                             }
                         }
 
                         index++;
                     }
                 }
-            }
 
-            return GetStream(img);
+                return GetStream(wand, appPaths);
+            }
         }
 
         public static async Task<Stream> GetSquareCollage(List<string> files,
             IFileSystem fileSystem,
-            int size)
+            int size, IApplicationPaths appPaths)
         {
+            if (files.Any(string.IsNullOrWhiteSpace))
+            {
+                throw new ArgumentException("Empty file found in files list");
+            }
+
+            if (files.Count == 0)
+            {
+                return null;
+            }
+
             if (files.Count < 4)
             {
                 return await GetSingleImage(files, fileSystem).ConfigureAwait(false);
@@ -85,16 +89,8 @@ namespace MediaBrowser.Server.Implementations.Photos
             int singleSize = size / 2;
             var index = 0;
 
-            var img = new Bitmap(size, size, PixelFormat.Format32bppPArgb);
-
-            using (var graphics = Graphics.FromImage(img))
+            using (var wand = new MagickWand(size, size, new PixelWand(ColorName.None, 1)))
             {
-                graphics.CompositingQuality = CompositingQuality.HighQuality;
-                graphics.SmoothingMode = SmoothingMode.HighQuality;
-                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
-                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
-                graphics.CompositingMode = CompositingMode.SourceCopy;
-
                 for (var row = 0; row < rows; row++)
                 {
                     for (var col = 0; col < cols; col++)
@@ -102,27 +98,18 @@ namespace MediaBrowser.Server.Implementations.Photos
                         var x = col * singleSize;
                         var y = row * singleSize;
 
-                        using (var fileStream = fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+                        using (var innerWand = new MagickWand(files[index]))
                         {
-                            using (var memoryStream = new MemoryStream())
-                            {
-                                await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
-                                memoryStream.Position = 0;
-
-                                using (var imgtemp = Image.FromStream(memoryStream, true, false))
-                                {
-                                    graphics.DrawImage(imgtemp, x, y, singleSize, singleSize);
-                                }
-                            }
+                            innerWand.CurrentImage.ResizeImage(singleSize, singleSize);
+                            wand.CurrentImage.CompositeImage(innerWand, CompositeOperator.OverCompositeOp, x, y);
                         }
 
                         index++;
                     }
                 }
-            }
 
-            return GetStream(img);
+                return GetStream(wand, appPaths);
+            }
         }
 
         private static Task<Stream> GetSingleImage(List<string> files, IFileSystem fileSystem)
@@ -130,29 +117,16 @@ namespace MediaBrowser.Server.Implementations.Photos
             return Task.FromResult<Stream>(fileSystem.GetFileStream(files[0], FileMode.Open, FileAccess.Read, FileShare.Read));
         }
 
-        private static Stream GetStream(Image image)
+        internal static Stream GetStream(MagickWand image, IApplicationPaths appPaths)
         {
-            var ms = new MemoryStream();
+            var tempFile = Path.Combine(appPaths.TempDirectory, Guid.NewGuid().ToString("N") + ".png");
 
-            image.Save(ms, ImageFormat.Png);
+            Directory.CreateDirectory(Path.GetDirectoryName(tempFile));
 
-            ms.Position = 0;
+            image.CurrentImage.CompressionQuality = 100;
+            image.SaveImage(tempFile);
 
-            return ms;
-        }
-
-        private static async Task<Image> GetImage(string file, IFileSystem fileSystem)
-        {
-            using (var fileStream = fileSystem.GetFileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, true))
-            {
-                var memoryStream = new MemoryStream();
-
-                await fileStream.CopyToAsync(memoryStream).ConfigureAwait(false);
-
-                memoryStream.Position = 0;
-
-                return Image.FromStream(memoryStream, true, false);
-            }
+            return File.OpenRead(tempFile);
         }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Photos/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/DynamicImageProvider.cs
deleted file mode 100644
index f3e48c4123..0000000000
--- a/MediaBrowser.Server.Implementations/Photos/DynamicImageProvider.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
-using MoreLinq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Photos
-{
-    public class MusicDynamicImageProvider : BaseDynamicImageProvider<UserView>, ICustomMetadataProvider<UserView>
-    {
-        private readonly IUserManager _userManager;
-        private readonly ILibraryManager _libraryManager;
-
-        public MusicDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IUserManager userManager, ILibraryManager libraryManager)
-            : base(fileSystem, providerManager)
-        {
-            _userManager = userManager;
-            _libraryManager = libraryManager;
-        }
-
-        protected override async Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
-        {
-            var view = (UserView)item;
-
-            if (!view.UserId.HasValue)
-            {
-                return new List<BaseItem>();
-            }
-
-            if (string.Equals(view.ViewType, SpecialFolder.GameGenre, StringComparison.OrdinalIgnoreCase))
-            {
-                var list = new List<BaseItem>();
-
-                var genre = _libraryManager.GetGameGenre(view.Name);
-
-                if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
-                {
-                    list.Add(genre);
-                }
-                return list;
-            }
-            if (string.Equals(view.ViewType, SpecialFolder.MusicGenre, StringComparison.OrdinalIgnoreCase))
-            {
-                var list = new List<BaseItem>();
-
-                var genre = _libraryManager.GetMusicGenre(view.Name);
-
-                if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
-                {
-                    list.Add(genre);
-                }
-                return list;
-            }
-            if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
-                string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
-            {
-                var list = new List<BaseItem>();
-
-                var genre = _libraryManager.GetGenre(view.Name);
-
-                if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
-                {
-                    list.Add(genre);
-                }
-                return list;
-            }
-
-            var result = await view.GetItems(new InternalItemsQuery
-            {
-                User = _userManager.GetUserById(view.UserId.Value)
-
-            }).ConfigureAwait(false);
-
-            var items = result.Items.Select(i =>
-            {
-                var episode = i as Episode;
-                if (episode != null)
-                {
-                    var series = episode.Series;
-                    if (series != null)
-                    {
-                        return series;
-                    }
-                    var episodeSeason = episode.Season;
-                    if (episodeSeason != null)
-                    {
-                        return episodeSeason;
-                    }
-
-                    return episode;
-                }
-
-                var season = i as Season;
-                if (season != null)
-                {
-                    var series = season.Series;
-                    if (series != null)
-                    {
-                        return series;
-                    }
-
-                    return season;
-                }
-
-                return i;
-
-            }).DistinctBy(i => i.Id);
-
-            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)).ToList());
-        }
-
-        protected override bool Supports(IHasImages item)
-        {
-            var view = item as UserView;
-
-            if (view != null && view.UserId.HasValue)
-            {
-                var supported = new[]
-                {
-                    SpecialFolder.TvFavoriteEpisodes,
-                    SpecialFolder.TvFavoriteSeries,
-                    SpecialFolder.TvGenres,
-                    SpecialFolder.TvGenre,
-                    SpecialFolder.TvLatest,
-                    SpecialFolder.TvNextUp,
-                    SpecialFolder.TvResume,
-                    SpecialFolder.TvShowSeries,
-
-                    SpecialFolder.MovieCollections,
-                    SpecialFolder.MovieFavorites,
-                    SpecialFolder.MovieGenres,
-                    SpecialFolder.MovieGenre,
-                    SpecialFolder.MovieLatest,
-                    SpecialFolder.MovieMovies,
-                    SpecialFolder.MovieResume,
-
-                    SpecialFolder.GameFavorites,
-                    SpecialFolder.GameGenres,
-                    SpecialFolder.GameGenre,
-                    SpecialFolder.GameSystems,
-                    SpecialFolder.LatestGames,
-                    SpecialFolder.RecentlyPlayedGames,
-
-                    SpecialFolder.MusicArtists,
-                    SpecialFolder.MusicAlbumArtists,
-                    SpecialFolder.MusicAlbums,
-                    SpecialFolder.MusicGenres,
-                    SpecialFolder.MusicGenre,
-                    SpecialFolder.MusicLatest,
-                    SpecialFolder.MusicSongs,
-                    SpecialFolder.MusicFavorites,
-                    SpecialFolder.MusicFavoriteArtists,
-                    SpecialFolder.MusicFavoriteAlbums,
-                    SpecialFolder.MusicFavoriteSongs
-                };
-
-                return supported.Contains(view.ViewType, StringComparer.OrdinalIgnoreCase) &&
-                    _userManager.GetUserById(view.UserId.Value) != null;
-            }
-
-            return false;
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
index 6a3759f134..73d9183a5d 100644
--- a/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Providers;
 using System.Collections.Generic;
@@ -7,10 +8,9 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Photos
 {
-    public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>, ICustomMetadataProvider<PhotoAlbum>
+    public class PhotoAlbumImageProvider : BaseDynamicImageProvider<PhotoAlbum>
     {
-        public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager)
-            : base(fileSystem, providerManager)
+        public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
         {
         }
 
diff --git a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
index aa10e66355..81f9438b9f 100644
--- a/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
+++ b/MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.TV;
@@ -13,9 +14,9 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Playlists
 {
-    public class PlaylistImageProvider : BaseDynamicImageProvider<Playlist>, ICustomMetadataProvider<Playlist>
+    public class PlaylistImageProvider : BaseDynamicImageProvider<Playlist>
     {
-        public PlaylistImageProvider(IFileSystem fileSystem, IProviderManager providerManager) : base(fileSystem, providerManager)
+        public PlaylistImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths) : base(fileSystem, providerManager, applicationPaths)
         {
         }
 
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index 7132db2efe..b23aaeeffa 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -4,9 +4,7 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
-using MoreLinq;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -30,10 +28,6 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         /// </summary>
         private readonly ILibraryManager _libraryManager;
 
-        private readonly List<Video> _newlyAddedItems = new List<Video>();
-
-        private const int NewItemDelay = 30000;
-
         /// <summary>
         /// The current new item timer
         /// </summary>
@@ -59,70 +53,6 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
             _itemRepo = itemRepo;
             _appPaths = appPaths;
             _encodingManager = encodingManager;
-
-            libraryManager.ItemAdded += libraryManager_ItemAdded;
-            libraryManager.ItemUpdated += libraryManager_ItemAdded;
-        }
-
-        void libraryManager_ItemAdded(object sender, ItemChangeEventArgs e)
-        {
-            var video = e.Item as Video;
-
-            if (video != null)
-            {
-                lock (_newlyAddedItems)
-                {
-                    _newlyAddedItems.Add(video);
-
-                    if (NewItemTimer == null)
-                    {
-                        NewItemTimer = new Timer(NewItemTimerCallback, null, NewItemDelay, Timeout.Infinite);
-                    }
-                    else
-                    {
-                        NewItemTimer.Change(NewItemDelay, Timeout.Infinite);
-                    }
-                }
-            }
-        }
-
-        private async void NewItemTimerCallback(object state)
-        {
-            List<Video> newItems;
-
-            // Lock the list and release all resources
-            lock (_newlyAddedItems)
-            {
-                newItems = _newlyAddedItems.DistinctBy(i => i.Id).ToList();
-                _newlyAddedItems.Clear();
-
-                NewItemTimer.Dispose();
-                NewItemTimer = null;
-            }
-
-            // Limit to video files to reduce changes of ffmpeg crash dialog
-            foreach (var item in newItems
-                .Where(i => i.LocationType == LocationType.FileSystem && i.VideoType == VideoType.VideoFile && string.IsNullOrEmpty(i.PrimaryImagePath) && i.DefaultVideoStreamIndex.HasValue)
-                .Take(1))
-            {
-                try
-                {
-                    var chapters = _itemRepo.GetChapters(item.Id).ToList();
-
-                    await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions
-                    {
-                        SaveChapters = true,
-                        ExtractImages = true,
-                        Video = item,
-                        Chapters = chapters
-
-                    }, CancellationToken.None);
-                }
-                catch (Exception ex)
-                {
-                    _logger.ErrorException("Error creating image for {0}", ex, item.Name);
-                }
-            }
         }
 
         /// <summary>
@@ -133,7 +63,14 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         {
             return new ITaskTrigger[]
                 {
-                    new DailyTrigger { TimeOfDay = TimeSpan.FromHours(4) }
+                    new DailyTrigger
+                    {
+                        TimeOfDay = TimeSpan.FromHours(1),
+                        TaskOptions = new TaskExecutionOptions
+                        {
+                            MaxRuntimeMs = Convert.ToInt32(TimeSpan.FromHours(4).TotalMilliseconds)
+                        }
+                    }
                 };
         }
 
diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
index cd20ad74dd..df7cc47f4d 100644
--- a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs
@@ -37,7 +37,7 @@ namespace MediaBrowser.Server.Implementations.Security
 
             string[] queries = {
 
-                                "create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)",
+                                "create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, AppVersion TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)",
                                 "create index if not exists idx_AccessTokens on AccessTokens(Id)",
 
                                 //pragmas
@@ -48,18 +48,21 @@ namespace MediaBrowser.Server.Implementations.Security
 
             _connection.RunQueries(queries, _logger);
 
+            _connection.AddColumn(_logger, "AccessTokens", "AppVersion", "TEXT");
+
             PrepareStatements();
         }
 
         private void PrepareStatements()
         {
             _saveInfoCommand = _connection.CreateCommand();
-            _saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
+            _saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)";
 
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@Id");
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AccessToken");
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceId");
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppName");
+            _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppVersion");
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceName");
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@UserId");
             _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@IsActive");
@@ -97,6 +100,7 @@ namespace MediaBrowser.Server.Implementations.Security
                 _saveInfoCommand.GetParameter(index++).Value = info.AccessToken;
                 _saveInfoCommand.GetParameter(index++).Value = info.DeviceId;
                 _saveInfoCommand.GetParameter(index++).Value = info.AppName;
+                _saveInfoCommand.GetParameter(index++).Value = info.AppVersion;
                 _saveInfoCommand.GetParameter(index++).Value = info.DeviceName;
                 _saveInfoCommand.GetParameter(index++).Value = info.UserId;
                 _saveInfoCommand.GetParameter(index++).Value = info.IsActive;
@@ -140,7 +144,7 @@ namespace MediaBrowser.Server.Implementations.Security
             }
         }
 
-        private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens";
+        private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens";
 
         public QueryResult<AuthenticationInfo> Get(AuthenticationInfoQuery query)
         {
@@ -264,8 +268,6 @@ namespace MediaBrowser.Server.Implementations.Security
 
         private AuthenticationInfo Get(IDataReader reader)
         {
-            var s = "select Id, AccessToken, DeviceId, AppName, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens";
-
             var info = new AuthenticationInfo
             {
                 Id = reader.GetGuid(0).ToString("N"),
@@ -284,20 +286,25 @@ namespace MediaBrowser.Server.Implementations.Security
 
             if (!reader.IsDBNull(4))
             {
-                info.DeviceName = reader.GetString(4);
+                info.AppVersion = reader.GetString(4);
             }
-            
+
             if (!reader.IsDBNull(5))
             {
-                info.UserId = reader.GetString(5);
+                info.DeviceName = reader.GetString(5);
+            }
+            
+            if (!reader.IsDBNull(6))
+            {
+                info.UserId = reader.GetString(6);
             }
 
-            info.IsActive = reader.GetBoolean(6);
-            info.DateCreated = reader.GetDateTime(7).ToUniversalTime();
+            info.IsActive = reader.GetBoolean(7);
+            info.DateCreated = reader.GetDateTime(8).ToUniversalTime();
 
-            if (!reader.IsDBNull(8))
+            if (!reader.IsDBNull(9))
             {
-                info.DateRevoked = reader.GetDateTime(8).ToUniversalTime();
+                info.DateRevoked = reader.GetDateTime(9).ToUniversalTime();
             }
          
             return info;
diff --git a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
index ef2fef7466..8719f54489 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/ServerManager.cs
@@ -1,12 +1,14 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Events;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
+using System.Collections.Specialized;
 using System.Linq;
 using System.Net.Sockets;
 using System.Threading;
@@ -45,6 +47,8 @@ namespace MediaBrowser.Server.Implementations.ServerManager
             get { return _webSocketConnections; }
         }
 
+        public event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
+
         /// <summary>
         /// The _logger
         /// </summary>
@@ -141,10 +145,17 @@ namespace MediaBrowser.Server.Implementations.ServerManager
         {
             var connection = new WebSocketConnection(e.WebSocket, e.Endpoint, _jsonSerializer, _logger)
             {
-                OnReceive = ProcessWebSocketMessageReceived
+                OnReceive = ProcessWebSocketMessageReceived,
+                Url = e.Url,
+                QueryString = new NameValueCollection(e.QueryString ?? new NameValueCollection())
             };
 
             _webSocketConnections.Add(connection);
+
+            if (WebSocketConnected != null)
+            {
+                EventHelper.FireEventIfNotNull(WebSocketConnected, this, new GenericEventArgs<IWebSocketConnection> (connection), _logger);
+            }
         }
 
         /// <summary>
diff --git a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
index 9f75d522c9..44d8cc4371 100644
--- a/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
+++ b/MediaBrowser.Server.Implementations/ServerManager/WebSocketConnection.cs
@@ -1,12 +1,15 @@
-using MediaBrowser.Common.Events;
+using System.Text;
+using MediaBrowser.Common.Events;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Serialization;
 using System;
+using System.Collections.Specialized;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
+using UniversalDetector;
 
 namespace MediaBrowser.Server.Implementations.ServerManager
 {
@@ -65,6 +68,17 @@ namespace MediaBrowser.Server.Implementations.ServerManager
         /// <value>The id.</value>
         public Guid Id { get; private set; }
 
+        /// <summary>
+        /// Gets or sets the URL.
+        /// </summary>
+        /// <value>The URL.</value>
+        public string Url { get; set; }
+        /// <summary>
+        /// Gets or sets the query string.
+        /// </summary>
+        /// <value>The query string.</value>
+        public NameValueCollection QueryString { get; set; }
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
         /// </summary>
@@ -120,29 +134,43 @@ namespace MediaBrowser.Server.Implementations.ServerManager
             {
                 return;
             }
+            var charset = DetectCharset(bytes);
+
+            if (string.Equals(charset, "utf-8", StringComparison.OrdinalIgnoreCase))
+            {
+                OnReceiveInternal(Encoding.UTF8.GetString(bytes));
+            }
+            else
+            {
+                OnReceiveInternal(Encoding.ASCII.GetString(bytes));
+            }
+        }
+        private string DetectCharset(byte[] bytes)
+        {
             try
             {
-                WebSocketMessageInfo info;
-
-                using (var memoryStream = new MemoryStream(bytes))
+                using (var ms = new MemoryStream(bytes))
                 {
-                    var stub = (WebSocketMessage<object>)_jsonSerializer.DeserializeFromStream(memoryStream, typeof(WebSocketMessage<object>));
+                    var detector = new CharsetDetector();
+                    detector.Feed(ms);
+                    detector.DataEnd();
 
-                    info = new WebSocketMessageInfo
-                    {
-                        MessageType = stub.MessageType,
-                        Data = stub.Data == null ? null : stub.Data.ToString()
-                    };
-                }
+                    var charset = detector.Charset;
 
-                info.Connection = this;
+                    if (!string.IsNullOrWhiteSpace(charset))
+                    {
+                        //_logger.Debug("UniversalDetector detected charset {0}", charset);
+                    }
 
-                OnReceive(info);
+                    return charset;
+                }
             }
-            catch (Exception ex)
+            catch (IOException ex)
             {
-                _logger.ErrorException("Error processing web socket message", ex);
+                _logger.ErrorException("Error attempting to determine web socket message charset", ex);
             }
+
+            return null;
         }
 
         private void OnReceiveInternal(string message)
diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
index a9488190c4..5ea970426a 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs
@@ -202,7 +202,7 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <summary>
         /// Logs the user activity.
         /// </summary>
-        /// <param name="clientType">Type of the client.</param>
+        /// <param name="appName">Type of the client.</param>
         /// <param name="appVersion">The app version.</param>
         /// <param name="deviceId">The device id.</param>
         /// <param name="deviceName">Name of the device.</param>
@@ -211,16 +211,16 @@ namespace MediaBrowser.Server.Implementations.Session
         /// <returns>Task.</returns>
         /// <exception cref="System.ArgumentNullException">user</exception>
         /// <exception cref="System.UnauthorizedAccessException"></exception>
-        public async Task<SessionInfo> LogSessionActivity(string clientType,
+        public async Task<SessionInfo> LogSessionActivity(string appName,
             string appVersion,
             string deviceId,
             string deviceName,
             string remoteEndPoint,
             User user)
         {
-            if (string.IsNullOrEmpty(clientType))
+            if (string.IsNullOrEmpty(appName))
             {
-                throw new ArgumentNullException("clientType");
+                throw new ArgumentNullException("appName");
             }
             if (string.IsNullOrEmpty(appVersion))
             {
@@ -237,10 +237,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             var activityDate = DateTime.UtcNow;
 
-            var userId = user == null ? (Guid?)null : user.Id;
-            var username = user == null ? null : user.Name;
-
-            var session = await GetSessionInfo(clientType, appVersion, deviceId, deviceName, remoteEndPoint, userId, username).ConfigureAwait(false);
+            var session = await GetSessionInfo(appName, appVersion, deviceId, deviceName, remoteEndPoint, user).ConfigureAwait(false);
 
             session.LastActivityDate = activityDate;
 
@@ -281,7 +278,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
                 if (session != null)
                 {
-                    var key = GetSessionKey(session.Client, session.ApplicationVersion, session.DeviceId);
+                    var key = GetSessionKey(session.Client, session.DeviceId);
 
                     SessionInfo removed;
 
@@ -317,7 +314,10 @@ namespace MediaBrowser.Server.Implementations.Session
                 if (!string.Equals(info.ItemId, info.MediaSourceId) &&
                     !string.IsNullOrWhiteSpace(info.MediaSourceId))
                 {
-                    runtimeTicks = _libraryManager.GetItemById(new Guid(info.MediaSourceId)).RunTimeTicks;
+                    var runtimeItem = _libraryManager.GetItemById(new Guid(info.MediaSourceId)) ??
+                                      _libraryManager.GetItemById(info.ItemId);
+
+                    runtimeTicks = runtimeItem.RunTimeTicks;
                 }
 
                 var current = session.NowPlayingItem;
@@ -365,42 +365,44 @@ namespace MediaBrowser.Server.Implementations.Session
             }
         }
 
-        private string GetSessionKey(string clientType, string appVersion, string deviceId)
+        private string GetSessionKey(string appName, string deviceId)
         {
-            return clientType + deviceId;
+            return appName + deviceId;
         }
 
         /// <summary>
         /// Gets the connection.
         /// </summary>
-        /// <param name="clientType">Type of the client.</param>
+        /// <param name="appName">Type of the client.</param>
         /// <param name="appVersion">The app version.</param>
         /// <param name="deviceId">The device id.</param>
         /// <param name="deviceName">Name of the device.</param>
         /// <param name="remoteEndPoint">The remote end point.</param>
-        /// <param name="userId">The user identifier.</param>
-        /// <param name="username">The username.</param>
+        /// <param name="user">The user.</param>
         /// <returns>SessionInfo.</returns>
-        private async Task<SessionInfo> GetSessionInfo(string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Guid? userId, string username)
+        private async Task<SessionInfo> GetSessionInfo(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
         {
-            var key = GetSessionKey(clientType, appVersion, deviceId);
+            var key = GetSessionKey(appName, deviceId);
 
             await _sessionLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
 
+            var userId = user == null ? (Guid?)null : user.Id;
+            var username = user == null ? null : user.Name;
+
             try
             {
-                SessionInfo connection;
+                SessionInfo sessionInfo;
                 DeviceInfo device = null;
 
-                if (!_activeConnections.TryGetValue(key, out connection))
+                if (!_activeConnections.TryGetValue(key, out sessionInfo))
                 {
-                    var sessionInfo = new SessionInfo
-                    {
-                        Client = clientType,
-                        DeviceId = deviceId,
-                        ApplicationVersion = appVersion,
-                        Id = Guid.NewGuid().ToString("N")
-                    };
+                    sessionInfo = new SessionInfo
+                   {
+                       Client = appName,
+                       DeviceId = deviceId,
+                       ApplicationVersion = appVersion,
+                       Id = key.GetMD5().ToString("N")
+                   };
 
                     sessionInfo.DeviceName = deviceName;
                     sessionInfo.UserId = userId;
@@ -410,12 +412,11 @@ namespace MediaBrowser.Server.Implementations.Session
                     OnSessionStarted(sessionInfo);
 
                     _activeConnections.TryAdd(key, sessionInfo);
-                    connection = sessionInfo;
 
                     if (!string.IsNullOrEmpty(deviceId))
                     {
                         var userIdString = userId.HasValue ? userId.Value.ToString("N") : null;
-                        device = await _deviceManager.RegisterDevice(deviceId, deviceName, clientType, userIdString).ConfigureAwait(false);
+                        device = await _deviceManager.RegisterDevice(deviceId, deviceName, appName, appVersion, userIdString).ConfigureAwait(false);
                     }
                 }
 
@@ -426,24 +427,25 @@ namespace MediaBrowser.Server.Implementations.Session
                     deviceName = device.CustomName;
                 }
 
-                connection.DeviceName = deviceName;
-                connection.UserId = userId;
-                connection.UserName = username;
-                connection.RemoteEndPoint = remoteEndPoint;
+                sessionInfo.DeviceName = deviceName;
+                sessionInfo.UserId = userId;
+                sessionInfo.UserName = username;
+                sessionInfo.RemoteEndPoint = remoteEndPoint;
+                sessionInfo.ApplicationVersion = appVersion;
 
                 if (!userId.HasValue)
                 {
-                    connection.AdditionalUsers.Clear();
+                    sessionInfo.AdditionalUsers.Clear();
                 }
 
-                if (connection.SessionController == null)
+                if (sessionInfo.SessionController == null)
                 {
-                    connection.SessionController = _sessionFactories
-                        .Select(i => i.GetSessionController(connection))
+                    sessionInfo.SessionController = _sessionFactories
+                        .Select(i => i.GetSessionController(sessionInfo))
                         .FirstOrDefault(i => i != null);
                 }
 
-                return connection;
+                return sessionInfo;
             }
             finally
             {
@@ -798,6 +800,19 @@ namespace MediaBrowser.Server.Implementations.Session
             return session;
         }
 
+        private SessionInfo GetSessionToRemoteControl(string sessionId)
+        {
+            // Accept either device id or session id
+            var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId));
+
+            if (session == null)
+            {
+                throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId));
+            }
+
+            return session;
+        }
+
         public Task SendMessageCommand(string controllingSessionId, string sessionId, MessageCommand command, CancellationToken cancellationToken)
         {
             var generalCommand = new GeneralCommand
@@ -818,7 +833,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
         public Task SendGeneralCommand(string controllingSessionId, string sessionId, GeneralCommand command, CancellationToken cancellationToken)
         {
-            var session = GetSession(sessionId);
+            var session = GetSessionToRemoteControl(sessionId);
 
             var controllingSession = GetSession(controllingSessionId);
             AssertCanControl(session, controllingSession);
@@ -828,7 +843,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
         public Task SendPlayCommand(string controllingSessionId, string sessionId, PlayRequest command, CancellationToken cancellationToken)
         {
-            var session = GetSession(sessionId);
+            var session = GetSessionToRemoteControl(sessionId);
 
             var user = session.UserId.HasValue ? _userManager.GetUserById(session.UserId.Value) : null;
 
@@ -907,7 +922,7 @@ namespace MediaBrowser.Server.Implementations.Session
                 return FilterToSingleMediaType(items)
                     .OrderBy(i => i.SortName);
             }
-            
+
             if (item.IsFolder)
             {
                 var folder = (Folder)item;
@@ -955,7 +970,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
         public Task SendPlaystateCommand(string controllingSessionId, string sessionId, PlaystateRequest command, CancellationToken cancellationToken)
         {
-            var session = GetSession(sessionId);
+            var session = GetSessionToRemoteControl(sessionId);
 
             var controllingSession = GetSession(controllingSessionId);
             AssertCanControl(session, controllingSession);
@@ -1327,8 +1342,7 @@ namespace MediaBrowser.Server.Implementations.Session
             ClientCapabilities capabilities,
             bool saveCapabilities)
         {
-            session.PlayableMediaTypes = capabilities.PlayableMediaTypes;
-            session.SupportedCommands = capabilities.SupportedCommands;
+            session.Capabilities = capabilities;
 
             if (!string.IsNullOrWhiteSpace(capabilities.MessageCallbackUrl))
             {
@@ -1567,11 +1581,7 @@ namespace MediaBrowser.Server.Implementations.Session
 
             if (!string.IsNullOrWhiteSpace(mediaSourceId))
             {
-                info.MediaStreams = _mediaSourceManager.GetMediaStreams(new MediaStreamQuery
-                {
-                    ItemId = new Guid(mediaSourceId)
-
-                }).ToList();
+                info.MediaStreams = _mediaSourceManager.GetMediaStreams(mediaSourceId).ToList();
             }
 
             return info;
@@ -1632,6 +1642,64 @@ namespace MediaBrowser.Server.Implementations.Session
                 string.Equals(i.Client, client));
         }
 
+        public Task<SessionInfo> GetSessionByAuthenticationToken(AuthenticationInfo info, string deviceId, string remoteEndpoint, string appVersion)
+        {
+            if (info == null)
+            {
+                throw new ArgumentNullException("info");
+            }
+
+            var user = string.IsNullOrWhiteSpace(info.UserId)
+                ? null
+                : _userManager.GetUserById(info.UserId);
+
+            appVersion = string.IsNullOrWhiteSpace(appVersion)
+                ? info.AppVersion
+                : appVersion;
+
+            var deviceName = info.DeviceName;
+            var appName = info.AppName;
+
+            if (!string.IsNullOrWhiteSpace(deviceId))
+            {
+                // Replace the info from the token with more recent info
+                var device = _deviceManager.GetDevice(deviceId);
+                if (device != null)
+                {
+                    deviceName = device.Name;
+                    appName = device.AppName;
+
+                    if (!string.IsNullOrWhiteSpace(device.AppVersion))
+                    {
+                        appVersion = device.AppVersion;
+                    }
+                }
+            }
+            else
+            {
+                deviceId = info.DeviceId;
+            }
+
+            return GetSessionInfo(appName, appVersion, deviceId, deviceName, remoteEndpoint, user);
+        }
+
+        public Task<SessionInfo> GetSessionByAuthenticationToken(string token, string deviceId, string remoteEndpoint)
+        {
+            var result = _authRepo.Get(new AuthenticationInfoQuery
+            {
+                AccessToken = token
+            });
+
+            var info = result.Items.FirstOrDefault();
+
+            if (info == null)
+            {
+                return Task.FromResult<SessionInfo>(null);
+            }
+
+            return GetSessionByAuthenticationToken(info, deviceId, remoteEndpoint, null);
+        }
+
         public Task SendMessageToUserSessions<T>(string userId, string name, T data,
             CancellationToken cancellationToken)
         {
diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
index 36a7fcbd8a..b8cab0c199 100644
--- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -1,10 +1,11 @@
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Net;
+using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Session;
 using System;
+using System.Collections.Specialized;
 using System.Globalization;
 using System.Linq;
 using System.Threading.Tasks;
@@ -14,7 +15,7 @@ namespace MediaBrowser.Server.Implementations.Session
     /// <summary>
     /// Class SessionWebSocketListener
     /// </summary>
-    public class SessionWebSocketListener : IWebSocketListener
+    public class SessionWebSocketListener : IWebSocketListener, IDisposable
     {
         /// <summary>
         /// The _true task result
@@ -36,17 +37,86 @@ namespace MediaBrowser.Server.Implementations.Session
         /// </summary>
         private readonly IJsonSerializer _json;
 
+        private readonly IHttpServer _httpServer;
+        private readonly IServerManager _serverManager;
+
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SessionWebSocketListener" /> class.
         /// </summary>
         /// <param name="sessionManager">The session manager.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="json">The json.</param>
-        public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json)
+        /// <param name="httpServer">The HTTP server.</param>
+        /// <param name="serverManager">The server manager.</param>
+        public SessionWebSocketListener(ISessionManager sessionManager, ILogManager logManager, IJsonSerializer json, IHttpServer httpServer, IServerManager serverManager)
         {
             _sessionManager = sessionManager;
             _logger = logManager.GetLogger(GetType().Name);
             _json = json;
+            _httpServer = httpServer;
+            _serverManager = serverManager;
+            httpServer.WebSocketConnecting += _httpServer_WebSocketConnecting;
+            serverManager.WebSocketConnected += _serverManager_WebSocketConnected;
+        }
+
+        async void _serverManager_WebSocketConnected(object sender, GenericEventArgs<IWebSocketConnection> e)
+        {
+            var session = await GetSession(e.Argument.QueryString, e.Argument.RemoteEndPoint).ConfigureAwait(false);
+
+            if (session != null)
+            {
+                var controller = session.SessionController as WebSocketController;
+
+                if (controller == null)
+                {
+                    controller = new WebSocketController(session, _logger, _sessionManager);
+                }
+
+                controller.AddWebSocket(e.Argument);
+
+                session.SessionController = controller;
+            }
+            else
+            {
+                _logger.Warn("Unable to determine session based on url: {0}", e.Argument.Url);
+            }
+        }
+
+        async void _httpServer_WebSocketConnecting(object sender, WebSocketConnectingEventArgs e)
+        {
+            var token = e.QueryString["api_key"];
+            if (!string.IsNullOrWhiteSpace(token))
+            {
+                var session = await GetSession(e.QueryString, e.Endpoint).ConfigureAwait(false);
+
+                if (session == null)
+                {
+                    e.AllowConnection = false;
+                }
+            }
+        }
+
+        private Task<SessionInfo> GetSession(NameValueCollection queryString, string remoteEndpoint)
+        {
+            if (queryString == null)
+            {
+                throw new ArgumentNullException("queryString");
+            }
+
+            var token = queryString["api_key"];
+            if (string.IsNullOrWhiteSpace(token))
+            {
+                return Task.FromResult<SessionInfo>(null);
+            }
+            var deviceId = queryString["deviceId"];
+            return _sessionManager.GetSessionByAuthenticationToken(token, deviceId, remoteEndpoint);
+        }
+
+        public void Dispose()
+        {
+            _httpServer.WebSocketConnecting -= _httpServer_WebSocketConnecting;
+            _serverManager.WebSocketConnected -= _serverManager_WebSocketConnected;
         }
 
         /// <summary>
diff --git a/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
new file mode 100644
index 0000000000..68cd44ec94
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
@@ -0,0 +1,70 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Sorting;
+using MediaBrowser.Model.Querying;
+using System;
+using System.Linq;
+
+namespace MediaBrowser.Server.Implementations.Sorting
+{
+    public class DateLastMediaAddedComparer : IUserBaseItemComparer
+    {
+        /// <summary>
+        /// Gets or sets the user.
+        /// </summary>
+        /// <value>The user.</value>
+        public User User { get; set; }
+
+        /// <summary>
+        /// Gets or sets the user manager.
+        /// </summary>
+        /// <value>The user manager.</value>
+        public IUserManager UserManager { get; set; }
+
+        /// <summary>
+        /// Gets or sets the user data repository.
+        /// </summary>
+        /// <value>The user data repository.</value>
+        public IUserDataManager UserDataRepository { get; set; }
+
+        /// <summary>
+        /// Compares the specified x.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <returns>System.Int32.</returns>
+        public int Compare(BaseItem x, BaseItem y)
+        {
+            return GetDate(x).CompareTo(GetDate(y));
+        }
+
+        /// <summary>
+        /// Gets the date.
+        /// </summary>
+        /// <param name="x">The x.</param>
+        /// <returns>DateTime.</returns>
+        private DateTime GetDate(BaseItem x)
+        {
+            var folder = x as Folder;
+
+            if (folder != null)
+            {
+                return folder.GetRecursiveChildren(User, i => !i.IsFolder)
+                    .Select(i => i.DateCreated)
+                    .OrderByDescending(i => i)
+                    .FirstOrDefault();
+            }
+
+            return x.DateCreated;
+        }
+
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return ItemSortBy.DateLastContentAdded; }
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
index 7605a7a50d..c881591beb 100644
--- a/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ b/MediaBrowser.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -1,6 +1,5 @@
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Model.Querying;
 using System;
diff --git a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
index d35ff8fc46..99d7582333 100644
--- a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs
@@ -3,12 +3,13 @@ using MediaBrowser.Controller.Sync;
 using MediaBrowser.Model.Devices;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Sync;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 
 namespace MediaBrowser.Server.Implementations.Sync
 {
-    public class AppSyncProvider : ISyncProvider, IHasUniqueTargetIds
+    public class AppSyncProvider : ISyncProvider, IHasUniqueTargetIds, IHasSyncQuality
     {
         private readonly IDeviceManager _deviceManager;
 
@@ -31,16 +32,77 @@ namespace MediaBrowser.Server.Implementations.Sync
             });
         }
 
-        public DeviceProfile GetDeviceProfile(SyncTarget target)
+        public DeviceProfile GetDeviceProfile(SyncTarget target, string profile, string quality)
         {
             var caps = _deviceManager.GetCapabilities(target.Id);
 
-            return caps == null || caps.DeviceProfile == null ? new DeviceProfile() : caps.DeviceProfile;
+            var deviceProfile = caps == null || caps.DeviceProfile == null ? new DeviceProfile() : caps.DeviceProfile;
+            deviceProfile.MaxStaticBitrate = SyncHelper.AdjustBitrate(deviceProfile.MaxStaticBitrate, quality);
+
+            return deviceProfile;
         }
 
         public string Name
         {
             get { return "App Sync"; }
         }
+
+        public IEnumerable<SyncTarget> GetAllSyncTargets()
+        {
+            return _deviceManager.GetDevices(new DeviceQuery
+            {
+                SupportsSync = true
+
+            }).Items.Select(i => new SyncTarget
+            {
+                Id = i.Id,
+                Name = i.Name
+            });
+        }
+
+        public IEnumerable<SyncQualityOption> GetQualityOptions(SyncTarget target)
+        {
+            return new List<SyncQualityOption>
+            {
+                new SyncQualityOption
+                {
+                    Name = "Original",
+                    Id = "original",
+                    Description = "Syncs original files as-is, regardless of whether the device is capable of playing them or not."
+                },
+                new SyncQualityOption
+                {
+                    Name = "High",
+                    Id = "high",
+                    IsDefault = true
+                },
+                new SyncQualityOption
+                {
+                    Name = "Medium",
+                    Id = "medium"
+                },
+                new SyncQualityOption
+                {
+                    Name = "Low",
+                    Id = "low"
+                }
+            };
+        }
+
+        public IEnumerable<SyncProfileOption> GetProfileOptions(SyncTarget target)
+        {
+            return new List<SyncProfileOption>();
+        }
+
+        public SyncJobOptions GetSyncJobOptions(SyncTarget target, string profile, string quality)
+        {
+            var isConverting = !string.Equals(quality, "original", StringComparison.OrdinalIgnoreCase);
+
+            return new SyncJobOptions
+            {
+                DeviceProfile = GetDeviceProfile(target, profile, quality),
+                IsConverting = isConverting
+            };
+        }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
new file mode 100644
index 0000000000..e13042538c
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs
@@ -0,0 +1,123 @@
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public class CloudSyncProfile : DeviceProfile
+    {
+        public CloudSyncProfile(bool supportsAc3, bool supportsDca)
+        {
+            Name = "Cloud Sync";
+
+            MaxStreamingBitrate = 20000000;
+            MaxStaticBitrate = 20000000;
+
+            var mkvAudio = "aac,mp3";
+            var mp4Audio = "aac";
+
+            if (supportsAc3)
+            {
+                mkvAudio += ",ac3";
+                mp4Audio += ",ac3";
+            }
+
+            if (supportsDca)
+            {
+                mkvAudio += ",dca";
+            }
+
+            DirectPlayProfiles = new[]
+            {
+                new DirectPlayProfile
+                {
+                    Container = "mkv",
+                    VideoCodec = "h264,mpeg4",
+                    AudioCodec = mkvAudio,
+                    Type = DlnaProfileType.Video
+                },
+                new DirectPlayProfile
+                {
+                    Container = "mp4,mov,m4v",
+                    VideoCodec = "h264,mpeg4",
+                    AudioCodec = mp4Audio,
+                    Type = DlnaProfileType.Video
+                },
+                new DirectPlayProfile
+                {
+                    Container = "mp3",
+                    Type = DlnaProfileType.Audio
+                }
+            };
+
+            ContainerProfiles = new ContainerProfile[] { };
+
+            CodecProfiles = new[]
+            {
+                new CodecProfile
+                {
+                    Type = CodecType.Video,
+                    Conditions = new []
+                    {
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoBitDepth,
+                            Value = "8",
+                            IsRequired = false
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.Height,
+                            Value = "1080",
+                            IsRequired = false
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.RefFrames,
+                            Value = "12",
+                            IsRequired = false
+                        }
+                    }
+                }
+            };
+
+            SubtitleProfiles = new[]
+            {
+                new SubtitleProfile
+                {
+                    Format = "srt",
+                    Method = SubtitleDeliveryMethod.External
+                }
+            };
+
+            TranscodingProfiles = new[]
+            {
+                new TranscodingProfile
+                {
+                    Container = "mp3",
+                    AudioCodec = "mp3",
+                    Type = DlnaProfileType.Audio,
+                    Context = EncodingContext.Static
+                },
+
+                new TranscodingProfile
+                {
+                    Container = "mp4",
+                    Type = DlnaProfileType.Video,
+                    AudioCodec = "aac",
+                    VideoCodec = "h264",
+                    Context = EncodingContext.Static
+                },
+
+                new TranscodingProfile
+                {
+                    Container = "jpeg",
+                    Type = DlnaProfileType.Photo,
+                    Context = EncodingContext.Static
+                }
+            };
+
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProvider.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProvider.cs
deleted file mode 100644
index 59713b1384..0000000000
--- a/MediaBrowser.Server.Implementations/Sync/CloudSyncProvider.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Controller.Sync;
-using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Sync;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Server.Implementations.Sync
-{
-    public class CloudSyncProvider : IServerSyncProvider
-    {
-        private readonly ICloudSyncProvider[] _providers = {};
-
-        public CloudSyncProvider(IApplicationHost appHost)
-        {
-            _providers = appHost.GetExports<ICloudSyncProvider>().ToArray();
-        }
-
-        public IEnumerable<SyncTarget> GetSyncTargets(string userId)
-        {
-            return _providers.SelectMany(i => i.GetSyncTargets(userId));
-        }
-
-        public DeviceProfile GetDeviceProfile(SyncTarget target)
-        {
-            return new DeviceProfile();
-        }
-
-        public string Name
-        {
-            get { return "Cloud Sync"; }
-        }
-
-        public Task<List<string>> GetServerItemIds(string serverId, SyncTarget target, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task DeleteItem(string serverId, string itemId, SyncTarget target, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task TransferItemFile(string serverId, string itemId, string[] pathParts, string name, ItemFileType fileType, SyncTarget target, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}
diff --git a/MediaBrowser.Server.Implementations/Sync/IHasSyncQuality.cs b/MediaBrowser.Server.Implementations/Sync/IHasSyncQuality.cs
new file mode 100644
index 0000000000..e7eee09232
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/IHasSyncQuality.cs
@@ -0,0 +1,31 @@
+using MediaBrowser.Model.Sync;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public interface IHasSyncQuality
+    {
+        /// <summary>
+        /// Gets the device profile.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <param name="profile">The profile.</param>
+        /// <param name="quality">The quality.</param>
+        /// <returns>DeviceProfile.</returns>
+        SyncJobOptions GetSyncJobOptions(SyncTarget target, string profile, string quality);
+        
+        /// <summary>
+        /// Gets the quality options.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
+        IEnumerable<SyncQualityOption> GetQualityOptions(SyncTarget target);
+
+        /// <summary>
+        /// Gets the profile options.
+        /// </summary>
+        /// <param name="target">The target.</param>
+        /// <returns>IEnumerable&lt;SyncQualityOption&gt;.</returns>
+        IEnumerable<SyncProfileOption> GetProfileOptions(SyncTarget target);
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
index 099e45a6eb..c9ed4637a6 100644
--- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
@@ -1,9 +1,18 @@
-using MediaBrowser.Common.Progress;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Progress;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Sync;
 using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -14,26 +23,25 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly ISyncManager _syncManager;
         private readonly IServerApplicationHost _appHost;
         private readonly ILogger _logger;
+        private readonly IFileSystem _fileSystem;
 
-        public MediaSync(ILogger logger, ISyncManager syncManager, IServerApplicationHost appHost)
+        public MediaSync(ILogger logger, ISyncManager syncManager, IServerApplicationHost appHost, IFileSystem fileSystem)
         {
             _logger = logger;
             _syncManager = syncManager;
             _appHost = appHost;
+            _fileSystem = fileSystem;
         }
 
-        public async Task Sync(IServerSyncProvider provider, 
+        public async Task Sync(IServerSyncProvider provider,
+            ISyncDataProvider dataProvider,
             SyncTarget target,
             IProgress<double> progress,
             CancellationToken cancellationToken)
         {
             var serverId = _appHost.SystemId;
 
-            await SyncData(provider, serverId, target, cancellationToken).ConfigureAwait(false);
-            progress.Report(2);
-
-            // Do the data sync twice so the server knows what was removed from the device
-            await SyncData(provider, serverId, target, cancellationToken).ConfigureAwait(false);
+            await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false);
             progress.Report(3);
 
             var innerProgress = new ActionableProgress<double>();
@@ -43,16 +51,21 @@ namespace MediaBrowser.Server.Implementations.Sync
                 totalProgress += 1;
                 progress.Report(totalProgress);
             });
-            await GetNewMedia(provider, target, serverId, innerProgress, cancellationToken);
+            await GetNewMedia(provider, dataProvider, target, serverId, innerProgress, cancellationToken);
+
+            // Do the data sync twice so the server knows what was removed from the device
+            await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false);
+
             progress.Report(100);
         }
 
         private async Task SyncData(IServerSyncProvider provider,
+            ISyncDataProvider dataProvider,
             string serverId,
             SyncTarget target,
             CancellationToken cancellationToken)
         {
-            var localIds = await provider.GetServerItemIds(serverId, target, cancellationToken).ConfigureAwait(false);
+            var localIds = await dataProvider.GetServerItemIds(target, serverId).ConfigureAwait(false);
 
             var result = await _syncManager.SyncData(new SyncDataRequest
             {
@@ -67,23 +80,24 @@ namespace MediaBrowser.Server.Implementations.Sync
             {
                 try
                 {
-                    await RemoveItem(provider, serverId, itemIdToRemove, target, cancellationToken).ConfigureAwait(false);
+                    await RemoveItem(provider, dataProvider, serverId, itemIdToRemove, target, cancellationToken).ConfigureAwait(false);
                 }
                 catch (Exception ex)
                 {
-                    _logger.ErrorException("Error deleting item from sync target. Id: {0}", ex, itemIdToRemove);
+                    _logger.ErrorException("Error deleting item from device. Id: {0}", ex, itemIdToRemove);
                 }
             }
         }
 
         private async Task GetNewMedia(IServerSyncProvider provider,
+            ISyncDataProvider dataProvider,
             SyncTarget target,
             string serverId,
             IProgress<double> progress,
             CancellationToken cancellationToken)
         {
-            var jobItems =  await _syncManager.GetReadySyncItems(target.Id).ConfigureAwait(false);
-            
+            var jobItems = await _syncManager.GetReadySyncItems(target.Id).ConfigureAwait(false);
+
             var numComplete = 0;
             double startingPercent = 0;
             double percentPerItem = 1;
@@ -105,7 +119,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                     progress.Report(totalProgress);
                 });
 
-                await GetItem(provider, target, serverId, jobItem, innerProgress, cancellationToken).ConfigureAwait(false);
+                await GetItem(provider, dataProvider, target, serverId, jobItem, innerProgress, cancellationToken).ConfigureAwait(false);
 
                 numComplete++;
                 startingPercent = numComplete;
@@ -116,6 +130,7 @@ namespace MediaBrowser.Server.Implementations.Sync
         }
 
         private async Task GetItem(IServerSyncProvider provider,
+            ISyncDataProvider dataProvider,
             SyncTarget target,
             string serverId,
             SyncedItem jobItem,
@@ -128,6 +143,8 @@ namespace MediaBrowser.Server.Implementations.Sync
             var fileTransferProgress = new ActionableProgress<double>();
             fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92));
 
+            var localItem = CreateLocalItem(provider, jobItem.SyncJobId, jobItem.SyncJobItemId, target, libraryItem, serverId, jobItem.OriginalFileName);
+
             await _syncManager.ReportSyncJobItemTransferBeginning(internalSyncJobItem.Id);
 
             var transferSuccess = false;
@@ -135,8 +152,21 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             try
             {
-                //await provider.TransferItemFile(serverId, libraryItem.Id, internalSyncJobItem.OutputPath, target, cancellationToken)
-                //        .ConfigureAwait(false);
+                var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem, target, cancellationToken).ConfigureAwait(false);
+
+                if (localItem.Item.MediaSources != null)
+                {
+                    var mediaSource = localItem.Item.MediaSources.FirstOrDefault();
+                    if (mediaSource != null)
+                    {
+                        mediaSource.Path = sendFileResult.Path;
+                        mediaSource.Protocol = sendFileResult.Protocol;
+                        mediaSource.SupportsTranscoding = false;
+                    }
+                }
+
+                // Create db record
+                await dataProvider.AddOrUpdate(target, localItem).ConfigureAwait(false);
 
                 progress.Report(92);
 
@@ -162,13 +192,176 @@ namespace MediaBrowser.Server.Implementations.Sync
             }
         }
 
-        private Task RemoveItem(IServerSyncProvider provider,
+        private async Task RemoveItem(IServerSyncProvider provider,
+            ISyncDataProvider dataProvider,
             string serverId,
             string itemId,
             SyncTarget target,
             CancellationToken cancellationToken)
         {
-            return provider.DeleteItem(serverId, itemId, target, cancellationToken);
+            var localItems = await dataProvider.GetCachedItems(target, serverId, itemId);
+
+            foreach (var localItem in localItems)
+            {
+                var files = await GetFiles(provider, localItem, target, cancellationToken);
+
+                foreach (var file in files)
+                {
+                    await provider.DeleteFile(file.Path, target, cancellationToken).ConfigureAwait(false);
+                }
+
+                await dataProvider.Delete(target, localItem.Id).ConfigureAwait(false);
+            }
+        }
+
+        private async Task<SendFileResult> SendFile(IServerSyncProvider provider, string inputPath, LocalItem item, SyncTarget target, CancellationToken cancellationToken)
+        {
+            using (var stream = _fileSystem.GetFileStream(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
+            {
+                return await provider.SendFile(stream, item.LocalPath, target, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+            }
+        }
+
+        private static string GetLocalId(string jobItemId, string itemId)
+        {
+            var bytes = Encoding.UTF8.GetBytes(jobItemId + itemId);
+            bytes = CreateMd5(bytes);
+            return BitConverter.ToString(bytes, 0, bytes.Length).Replace("-", string.Empty);
+        }
+
+        private static byte[] CreateMd5(byte[] value)
+        {
+            using (var provider = MD5.Create())
+            {
+                return provider.ComputeHash(value);
+            }
+        }
+
+        public LocalItem CreateLocalItem(IServerSyncProvider provider, string syncJobId, string syncJobItemId, SyncTarget target, BaseItemDto libraryItem, string serverId, string originalFileName)
+        {
+            var path = GetDirectoryPath(provider, syncJobId, libraryItem, serverId);
+            path.Add(GetLocalFileName(provider, libraryItem, originalFileName));
+
+            var localPath = provider.GetFullPath(path, target);
+
+            foreach (var mediaSource in libraryItem.MediaSources)
+            {
+                mediaSource.Path = localPath;
+                mediaSource.Protocol = MediaProtocol.File;
+            }
+
+            return new LocalItem
+            {
+                Item = libraryItem,
+                ItemId = libraryItem.Id,
+                ServerId = serverId,
+                LocalPath = localPath,
+                Id = GetLocalId(syncJobItemId, libraryItem.Id)
+            };
+        }
+
+        private List<string> GetDirectoryPath(IServerSyncProvider provider, string syncJobId, BaseItemDto item, string serverId)
+        {
+            var parts = new List<string>
+            {
+                serverId,
+                syncJobId
+            };
+
+            if (item.IsType("episode"))
+            {
+                parts.Add("TV");
+                if (!string.IsNullOrWhiteSpace(item.SeriesName))
+                {
+                    parts.Add(item.SeriesName);
+                }
+            }
+            else if (item.IsVideo)
+            {
+                parts.Add("Videos");
+                parts.Add(item.Name);
+            }
+            else if (item.IsAudio)
+            {
+                parts.Add("Music");
+
+                if (!string.IsNullOrWhiteSpace(item.AlbumArtist))
+                {
+                    parts.Add(item.AlbumArtist);
+                }
+
+                if (!string.IsNullOrWhiteSpace(item.Album))
+                {
+                    parts.Add(item.Album);
+                }
+            }
+            else if (string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase))
+            {
+                parts.Add("Photos");
+
+                if (!string.IsNullOrWhiteSpace(item.Album))
+                {
+                    parts.Add(item.Album);
+                }
+            }
+
+            return parts.Select(i => GetValidFilename(provider, i)).ToList();
+        }
+
+        private string GetLocalFileName(IServerSyncProvider provider, BaseItemDto item, string originalFileName)
+        {
+            var filename = originalFileName;
+
+            if (string.IsNullOrWhiteSpace(filename))
+            {
+                filename = item.Name;
+            }
+
+            return GetValidFilename(provider, filename);
+        }
+
+        private string GetValidFilename(IServerSyncProvider provider, string filename)
+        {
+            // We can always add this method to the sync provider if it's really needed
+            return _fileSystem.GetValidFilename(filename);
+        }
+
+        private async Task<List<ItemFileInfo>> GetFiles(IServerSyncProvider provider, LocalItem item, SyncTarget target, CancellationToken cancellationToken)
+        {
+            var path = item.LocalPath;
+            path = provider.GetParentDirectoryPath(path, target);
+
+            var list = await provider.GetFileSystemEntries(path, target, cancellationToken).ConfigureAwait(false);
+
+            var itemFiles = new List<ItemFileInfo>();
+
+            var name = Path.GetFileNameWithoutExtension(item.LocalPath);
+
+            foreach (var file in list.Where(f => f.Name.Contains(name)))
+            {
+                var itemFile = new ItemFileInfo
+                {
+                    Path = file.Path,
+                    Name = file.Name
+                };
+
+                if (IsSubtitleFile(file.Name))
+                {
+                    itemFile.Type = ItemFileType.Subtitles;
+                }
+
+                itemFiles.Add(itemFile);
+            }
+
+            return itemFiles;
+        }
+
+        private static readonly string[] SupportedSubtitleExtensions = { ".srt", ".vtt" };
+        private bool IsSubtitleFile(string path)
+        {
+            var ext = Path.GetExtension(path) ?? string.Empty;
+
+            return SupportedSubtitleExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
         }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
new file mode 100644
index 0000000000..a8bc24c2a1
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs
@@ -0,0 +1,71 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Progress;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Sync;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public class MultiProviderSync
+    {
+        private readonly SyncManager _syncManager;
+        private readonly IServerApplicationHost _appHost;
+        private readonly ILogger _logger;
+        private readonly IFileSystem _fileSystem;
+
+        public MultiProviderSync(SyncManager syncManager, IServerApplicationHost appHost, ILogger logger, IFileSystem fileSystem)
+        {
+            _syncManager = syncManager;
+            _appHost = appHost;
+            _logger = logger;
+            _fileSystem = fileSystem;
+        }
+
+        public async Task Sync(IEnumerable<IServerSyncProvider> providers, IProgress<double> progress, CancellationToken cancellationToken)
+        {
+            var targets = providers
+                .SelectMany(i => i.GetAllSyncTargets().Select(t => new Tuple<IServerSyncProvider, SyncTarget>(i, t)))
+                .ToList();
+
+            var numComplete = 0;
+            double startingPercent = 0;
+            double percentPerItem = 1;
+            if (targets.Count > 0)
+            {
+                percentPerItem /= targets.Count;
+            }
+
+            foreach (var target in targets)
+            {
+                cancellationToken.ThrowIfCancellationRequested();
+
+                var currentPercent = startingPercent;
+                var innerProgress = new ActionableProgress<double>();
+                innerProgress.RegisterAction(pct =>
+                {
+                    var totalProgress = pct * percentPerItem;
+                    totalProgress += currentPercent;
+                    progress.Report(totalProgress);
+                });
+
+                var dataProvider = _syncManager.GetDataProvider(target.Item1, target.Item2);
+
+                await new MediaSync(_logger, _syncManager, _appHost, _fileSystem)
+                    .Sync(target.Item1, dataProvider, target.Item2, innerProgress, cancellationToken)
+                    .ConfigureAwait(false);
+
+                numComplete++;
+                startingPercent = numComplete;
+                startingPercent /= targets.Count;
+                startingPercent *= 100;
+                progress.Report(startingPercent);
+            }
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
new file mode 100644
index 0000000000..148602bd42
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs
@@ -0,0 +1,81 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    class ServerSyncScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
+    {
+        private readonly ISyncManager _syncManager;
+        private readonly ILogger _logger;
+        private readonly IFileSystem _fileSystem;
+        private readonly IServerApplicationHost _appHost;
+
+        public ServerSyncScheduledTask(ISyncManager syncManager, ILogger logger, IFileSystem fileSystem, IServerApplicationHost appHost)
+        {
+            _syncManager = syncManager;
+            _logger = logger;
+            _fileSystem = fileSystem;
+            _appHost = appHost;
+        }
+
+        public string Name
+        {
+            get { return "Cloud & Folder Sync"; }
+        }
+
+        public string Description
+        {
+            get { return "Sync media to the cloud"; }
+        }
+
+        public string Category
+        {
+            get
+            {
+                return "Sync";
+            }
+        }
+
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            return new MultiProviderSync((SyncManager)_syncManager, _appHost, _logger, _fileSystem)
+                .Sync(ServerSyncProviders, progress, cancellationToken);
+        }
+
+        public IEnumerable<IServerSyncProvider> ServerSyncProviders
+        {
+            get { return ((SyncManager)_syncManager).ServerSyncProviders; }
+        }
+        
+        public IEnumerable<ITaskTrigger> GetDefaultTriggers()
+        {
+            return new ITaskTrigger[]
+                {
+                    new IntervalTrigger { Interval = TimeSpan.FromHours(3) }
+                };
+        }
+
+        public bool IsHidden
+        {
+            get { return !IsEnabled; }
+        }
+
+        public bool IsEnabled
+        {
+            get { return ServerSyncProviders.Any(); }
+        }
+
+        public string Key
+        {
+            get { return "ServerSync"; }
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs
similarity index 80%
rename from MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
rename to MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs
index ccc9508e8a..913d50e9d7 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncConvertScheduledTask.cs
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Server.Implementations.Sync
 {
-    public class SyncScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
+    public class SyncConvertScheduledTask : IScheduledTask, IConfigurableScheduledTask, IHasKey
     {
         private readonly ILibraryManager _libraryManager;
         private readonly ISyncRepository _syncRepo;
@@ -25,8 +25,9 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly ISubtitleEncoder _subtitleEncoder;
         private readonly IConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
-        public SyncScheduledTask(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfigurationManager config, IFileSystem fileSystem)
+        public SyncConvertScheduledTask(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
         {
             _libraryManager = libraryManager;
             _syncRepo = syncRepo;
@@ -38,6 +39,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             _subtitleEncoder = subtitleEncoder;
             _config = config;
             _fileSystem = fileSystem;
+            _mediaSourceManager = mediaSourceManager;
         }
 
         public string Name
@@ -60,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
         public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
-            return new SyncJobProcessor(_libraryManager, _syncRepo, (SyncManager)_syncManager, _logger, _userManager, _tvSeriesManager, _mediaEncoder, _subtitleEncoder, _config, _fileSystem)
+            return new SyncJobProcessor(_libraryManager, _syncRepo, (SyncManager)_syncManager, _logger, _userManager, _tvSeriesManager, _mediaEncoder, _subtitleEncoder, _config, _fileSystem, _mediaSourceManager)
                 .Sync(progress, cancellationToken);
         }
 
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncHelper.cs b/MediaBrowser.Server.Implementations/Sync/SyncHelper.cs
new file mode 100644
index 0000000000..006284ee15
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/SyncHelper.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public class SyncHelper
+    {
+        public static int? AdjustBitrate(int? profileBitrate, string quality)
+        {
+            if (profileBitrate.HasValue)
+            {
+                if (string.Equals(quality, "medium", StringComparison.OrdinalIgnoreCase))
+                {
+                    profileBitrate = Convert.ToInt32(profileBitrate.Value * .75);
+                }
+                else if (string.Equals(quality, "low", StringComparison.OrdinalIgnoreCase))
+                {
+                    profileBitrate = Convert.ToInt32(profileBitrate.Value*.5);
+                }
+            }
+
+            return profileBitrate;
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobOptions.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobOptions.cs
new file mode 100644
index 0000000000..cb8141c895
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobOptions.cs
@@ -0,0 +1,18 @@
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public class SyncJobOptions
+    {
+        /// <summary>
+        /// Gets or sets the conversion options.
+        /// </summary>
+        /// <value>The conversion options.</value>
+        public DeviceProfile DeviceProfile { get; set; }
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is converting.
+        /// </summary>
+        /// <value><c>true</c> if this instance is converting; otherwise, <c>false</c>.</value>
+        public bool IsConverting { get; set; }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
index 72dc1bdb64..22c59610b9 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs
@@ -38,8 +38,9 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly ISubtitleEncoder _subtitleEncoder;
         private readonly IConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
+        private readonly IMediaSourceManager _mediaSourceManager;
 
-        public SyncJobProcessor(ILibraryManager libraryManager, ISyncRepository syncRepo, SyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfigurationManager config, IFileSystem fileSystem)
+        public SyncJobProcessor(ILibraryManager libraryManager, ISyncRepository syncRepo, SyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
         {
             _libraryManager = libraryManager;
             _syncRepo = syncRepo;
@@ -51,6 +52,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             _subtitleEncoder = subtitleEncoder;
             _config = config;
             _fileSystem = fileSystem;
+            _mediaSourceManager = mediaSourceManager;
         }
 
         public async Task EnsureJobItems(SyncJob job)
@@ -362,7 +364,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             // If it already has a converting status then is must have been aborted during conversion
             var result = _syncRepo.GetJobItems(new SyncJobItemQuery
             {
-                Statuses = new List<SyncJobItemStatus> { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting }
+                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting }
             });
 
             await SyncJobItems(result.Items, true, progress, cancellationToken).ConfigureAwait(false);
@@ -384,7 +386,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             // If it already has a converting status then is must have been aborted during conversion
             var result = _syncRepo.GetJobItems(new SyncJobItemQuery
             {
-                Statuses = new List<SyncJobItemStatus> { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
                 TargetId = targetId
             });
 
@@ -448,15 +450,6 @@ namespace MediaBrowser.Server.Implementations.Sync
                 return;
             }
 
-            var deviceProfile = _syncManager.GetDeviceProfile(jobItem.TargetId);
-            if (deviceProfile == null)
-            {
-                jobItem.Status = SyncJobItemStatus.Failed;
-                _logger.Error("Unable to locate SyncTarget for JobItem {0}, SyncTargetId {1}", jobItem.Id, jobItem.TargetId);
-                await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
-                return;
-            }
-
             jobItem.Progress = 0;
 
             var user = _userManager.GetUserById(job.UserId);
@@ -464,17 +457,17 @@ namespace MediaBrowser.Server.Implementations.Sync
             var video = item as Video;
             if (video != null)
             {
-                await Sync(jobItem, job, video, user, deviceProfile, enableConversion, progress, cancellationToken).ConfigureAwait(false);
+                await Sync(jobItem, job, video, user, enableConversion, progress, cancellationToken).ConfigureAwait(false);
             }
 
             else if (item is Audio)
             {
-                await Sync(jobItem, job, (Audio)item, user, deviceProfile, enableConversion, progress, cancellationToken).ConfigureAwait(false);
+                await Sync(jobItem, job, (Audio)item, user, enableConversion, progress, cancellationToken).ConfigureAwait(false);
             }
 
             else if (item is Photo)
             {
-                await Sync(jobItem, (Photo)item, deviceProfile, cancellationToken).ConfigureAwait(false);
+                await Sync(jobItem, (Photo)item, cancellationToken).ConfigureAwait(false);
             }
 
             else
@@ -483,17 +476,20 @@ namespace MediaBrowser.Server.Implementations.Sync
             }
         }
 
-        private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, DeviceProfile profile, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
+        private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var options = _syncManager.GetVideoOptions(jobItem, job);
+            var jobOptions = _syncManager.GetVideoOptions(jobItem, job);
+            var conversionOptions = new VideoOptions
+            {
+                Profile = jobOptions.DeviceProfile
+            };
 
-            options.DeviceId = jobItem.TargetId;
-            options.Context = EncodingContext.Static;
-            options.Profile = profile;
-            options.ItemId = item.Id.ToString("N");
-            options.MediaSources = item.GetMediaSources(false, user).ToList();
+            conversionOptions.DeviceId = jobItem.TargetId;
+            conversionOptions.Context = EncodingContext.Static;
+            conversionOptions.ItemId = item.Id.ToString("N");
+            conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList();
 
-            var streamInfo = new StreamBuilder().BuildVideoItem(options);
+            var streamInfo = new StreamBuilder().BuildVideoItem(conversionOptions);
             var mediaSource = streamInfo.MediaSource;
 
             // No sense creating external subs if we're already burning one into the video
@@ -502,7 +498,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                 streamInfo.GetExternalSubtitles(false);
 
             // Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted
-            var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && job.Quality != SyncQuality.Original;
+            var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting;
             var requiresConversion = requiresVideoTranscoding || externalSubs.Any(i => RequiresExtraction(i, mediaSource));
 
             if (requiresConversion && !enableConversion)
@@ -540,7 +536,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                         }
                     });
 
-                    jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, profile)
+                    jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile)
                     {
                         OutputDirectory = jobItem.TemporaryPath
 
@@ -583,6 +579,8 @@ namespace MediaBrowser.Server.Implementations.Sync
                 jobItem.MediaSource = mediaSource;
             }
 
+            jobItem.MediaSource.SupportsTranscoding = false;
+
             if (externalSubs.Count > 0)
             {
                 // Save the job item now since conversion could take a while
@@ -674,23 +672,26 @@ namespace MediaBrowser.Server.Implementations.Sync
 
         private const int DatabaseProgressUpdateIntervalSeconds = 2;
 
-        private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, DeviceProfile profile, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
+        private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var options = _syncManager.GetAudioOptions(jobItem);
+            var jobOptions = _syncManager.GetAudioOptions(jobItem, job);
+            var conversionOptions = new AudioOptions
+            {
+                Profile = jobOptions.DeviceProfile
+            };
 
-            options.DeviceId = jobItem.TargetId;
-            options.Context = EncodingContext.Static;
-            options.Profile = profile;
-            options.ItemId = item.Id.ToString("N");
-            options.MediaSources = item.GetMediaSources(false, user).ToList();
+            conversionOptions.DeviceId = jobItem.TargetId;
+            conversionOptions.Context = EncodingContext.Static;
+            conversionOptions.ItemId = item.Id.ToString("N");
+            conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList();
 
-            var streamInfo = new StreamBuilder().BuildAudioItem(options);
+            var streamInfo = new StreamBuilder().BuildAudioItem(conversionOptions);
             var mediaSource = streamInfo.MediaSource;
 
             jobItem.MediaSourceId = streamInfo.MediaSourceId;
             jobItem.TemporaryPath = GetTemporaryPath(jobItem);
 
-            if (streamInfo.PlayMethod == PlayMethod.Transcode && job.Quality != SyncQuality.Original)
+            if (streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting)
             {
                 if (!enableConversion)
                 {
@@ -717,7 +718,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                         }
                     });
 
-                    jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile)
+                    jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile)
                     {
                         OutputDirectory = jobItem.TemporaryPath
 
@@ -760,12 +761,14 @@ namespace MediaBrowser.Server.Implementations.Sync
                 jobItem.MediaSource = mediaSource;
             }
 
+            jobItem.MediaSource.SupportsTranscoding = false;
+
             jobItem.Progress = 50;
             jobItem.Status = SyncJobItemStatus.ReadyToTransfer;
             await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false);
         }
 
-        private async Task Sync(SyncJobItem jobItem, Photo item, DeviceProfile profile, CancellationToken cancellationToken)
+        private async Task Sync(SyncJobItem jobItem, Photo item, CancellationToken cancellationToken)
         {
             jobItem.OutputPath = item.Path;
 
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
index a2fd92bf50..dc539b4083 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs
@@ -15,16 +15,17 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.Sync;
 using MediaBrowser.Controller.TV;
-using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Querying;
+using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Sync;
 using MediaBrowser.Model.Users;
 using MoreLinq;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
@@ -47,7 +48,9 @@ namespace MediaBrowser.Server.Implementations.Sync
         private readonly IFileSystem _fileSystem;
         private readonly Func<ISubtitleEncoder> _subtitleEncoder;
         private readonly IConfigurationManager _config;
-        private IUserDataManager _userDataManager;
+        private readonly IUserDataManager _userDataManager;
+        private readonly Func<IMediaSourceManager> _mediaSourceManager;
+        private readonly IJsonSerializer _json;
 
         private ISyncProvider[] _providers = { };
 
@@ -57,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.Sync
         public event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemUpdated;
         public event EventHandler<GenericEventArgs<SyncJobItem>> SyncJobItemCreated;
 
-        public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func<IMediaEncoder> mediaEncoder, IFileSystem fileSystem, Func<ISubtitleEncoder> subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager)
+        public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func<IDtoService> dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func<IMediaEncoder> mediaEncoder, IFileSystem fileSystem, Func<ISubtitleEncoder> subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager, Func<IMediaSourceManager> mediaSourceManager, IJsonSerializer json)
         {
             _libraryManager = libraryManager;
             _repo = repo;
@@ -72,6 +75,8 @@ namespace MediaBrowser.Server.Implementations.Sync
             _subtitleEncoder = subtitleEncoder;
             _config = config;
             _userDataManager = userDataManager;
+            _mediaSourceManager = mediaSourceManager;
+            _json = json;
         }
 
         public void AddParts(IEnumerable<ISyncProvider> providers)
@@ -79,6 +84,19 @@ namespace MediaBrowser.Server.Implementations.Sync
             _providers = providers.ToArray();
         }
 
+        public IEnumerable<IServerSyncProvider> ServerSyncProviders
+        {
+            get { return _providers.OfType<IServerSyncProvider>(); }
+        }
+
+        private readonly ConcurrentDictionary<string, ISyncDataProvider> _dataProviders =
+            new ConcurrentDictionary<string, ISyncDataProvider>(StringComparer.OrdinalIgnoreCase);
+
+        public ISyncDataProvider GetDataProvider(IServerSyncProvider provider, SyncTarget target)
+        {
+            return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost.SystemId, _logger, _json, _fileSystem, _config.CommonApplicationPaths));
+        }
+
         public async Task<SyncJobCreationResult> CreateJob(SyncJobRequest request)
         {
             var processor = GetSyncJobProcessor();
@@ -117,6 +135,14 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             var jobId = Guid.NewGuid().ToString("N");
 
+            if (string.IsNullOrWhiteSpace(request.Quality))
+            {
+                request.Quality = GetQualityOptions(request.TargetId)
+                    .Where(i => i.IsDefault)
+                    .Select(i => i.Id)
+                    .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
+            }
+
             var job = new SyncJob
             {
                 Id = jobId,
@@ -130,9 +156,11 @@ namespace MediaBrowser.Server.Implementations.Sync
                 DateLastModified = DateTime.UtcNow,
                 SyncNewContent = request.SyncNewContent,
                 ItemCount = items.Count,
-                Quality = request.Quality,
                 Category = request.Category,
-                ParentId = request.ParentId
+                ParentId = request.ParentId,
+                Quality = request.Quality,
+                Profile = request.Profile,
+                Bitrate = request.Bitrate
             };
 
             if (!request.Category.HasValue && request.ItemIds != null)
@@ -155,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             // If it already has a converting status then is must have been aborted during conversion
             var jobItemsResult = _repo.GetJobItems(new SyncJobItemQuery
             {
-                Statuses = new List<SyncJobItemStatus> { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
                 JobId = jobId
             });
 
@@ -164,7 +192,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             jobItemsResult = _repo.GetJobItems(new SyncJobItemQuery
             {
-                Statuses = new List<SyncJobItemStatus> { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
+                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting },
                 JobId = jobId
             });
 
@@ -193,6 +221,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             instance.Name = job.Name;
             instance.Quality = job.Quality;
+            instance.Profile = job.Profile;
             instance.UnwatchedOnly = job.UnwatchedOnly;
             instance.SyncNewContent = job.SyncNewContent;
             instance.ItemLimit = job.ItemLimit;
@@ -407,6 +436,15 @@ namespace MediaBrowser.Server.Implementations.Sync
                 .OrderBy(i => i.Name);
         }
 
+        private IEnumerable<SyncTarget> GetSyncTargets(ISyncProvider provider)
+        {
+            return provider.GetAllSyncTargets().Select(i => new SyncTarget
+            {
+                Name = i.Name,
+                Id = GetSyncTargetId(provider, i)
+            });
+        }
+
         private IEnumerable<SyncTarget> GetSyncTargets(ISyncProvider provider, string userId)
         {
             return provider.GetSyncTargets(userId).Select(i => new SyncTarget
@@ -425,15 +463,9 @@ namespace MediaBrowser.Server.Implementations.Sync
                 return target.Id;
             }
 
-            var providerId = GetSyncProviderId(provider);
-            return (providerId + "-" + target.Id).GetMD5().ToString("N");
-        }
-
-        private ISyncProvider GetSyncProvider(SyncTarget target)
-        {
-            var providerId = target.Id.Split(new[] { '-' }, 2).First();
-
-            return _providers.First(i => string.Equals(providerId, GetSyncProviderId(i)));
+            return target.Id;
+            //var providerId = GetSyncProviderId(provider);
+            //return (providerId + "-" + target.Id).GetMD5().ToString("N");
         }
 
         private string GetSyncProviderId(ISyncProvider provider)
@@ -539,22 +571,6 @@ namespace MediaBrowser.Server.Implementations.Sync
             return item.Name;
         }
 
-        public DeviceProfile GetDeviceProfile(string targetId)
-        {
-            foreach (var provider in _providers)
-            {
-                foreach (var target in GetSyncTargets(provider, null))
-                {
-                    if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase))
-                    {
-                        return provider.GetDeviceProfile(target);
-                    }
-                }
-            }
-
-            return null;
-        }
-
         public async Task ReportSyncJobItemTransferred(string id)
         {
             var jobItem = _repo.GetJobItem(id);
@@ -586,7 +602,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
         private SyncJobProcessor GetSyncJobProcessor()
         {
-            return new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager, _mediaEncoder(), _subtitleEncoder(), _config, _fileSystem);
+            return new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager, _mediaEncoder(), _subtitleEncoder(), _config, _fileSystem, _mediaSourceManager());
         }
 
         public SyncJobItem GetJobItem(string id)
@@ -654,8 +670,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             syncedItem.Item = _dtoService().GetBaseItemDto(libraryItem, dtoOptions);
 
-            var mediaSource = syncedItem.Item.MediaSources
-               .FirstOrDefault(i => string.Equals(i.Id, jobItem.MediaSourceId));
+            var mediaSource = jobItem.MediaSource;
 
             syncedItem.Item.MediaSources = new List<MediaSourceInfo>();
 
@@ -704,7 +719,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             var jobItemResult = GetJobItems(new SyncJobItemQuery
             {
                 TargetId = targetId,
-                Statuses = new List<SyncJobItemStatus>
+                Statuses = new SyncJobItemStatus[]
                 {
                     SyncJobItemStatus.ReadyToTransfer
                 }
@@ -721,7 +736,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             var jobItemResult = GetJobItems(new SyncJobItemQuery
             {
                 TargetId = request.TargetId,
-                Statuses = new List<SyncJobItemStatus> { SyncJobItemStatus.Synced }
+                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Synced }
             });
 
             var response = new SyncDataResponse();
@@ -967,38 +982,178 @@ namespace MediaBrowser.Server.Implementations.Sync
             return _repo.GetLibraryItemIds(query);
         }
 
-        public AudioOptions GetAudioOptions(SyncJobItem jobItem)
+        public SyncJobOptions GetAudioOptions(SyncJobItem jobItem, SyncJob job)
         {
-            var profile = GetDeviceProfile(jobItem.TargetId);
+            var options = GetSyncJobOptions(jobItem.TargetId, null, null);
 
-            return new AudioOptions
+            if (job.Bitrate.HasValue)
             {
-                Profile = profile
-            };
+                options.DeviceProfile.MaxStaticBitrate = job.Bitrate.Value;
+            }
+
+            return options;
         }
 
-        public VideoOptions GetVideoOptions(SyncJobItem jobItem, SyncJob job)
+        public SyncJobOptions GetVideoOptions(SyncJobItem jobItem, SyncJob job)
         {
-            var profile = GetDeviceProfile(jobItem.TargetId);
-            var maxBitrate = profile.MaxStaticBitrate;
+            var options = GetSyncJobOptions(jobItem.TargetId, job.Profile, job.Quality);
+
+            if (job.Bitrate.HasValue)
+            {
+                options.DeviceProfile.MaxStaticBitrate = job.Bitrate.Value;
+            }
+
+            return options;
+        }
 
-            if (maxBitrate.HasValue)
+        private SyncJobOptions GetSyncJobOptions(string targetId, string profile, string quality)
+        {
+            foreach (var provider in _providers)
             {
-                if (job.Quality == SyncQuality.Medium)
+                foreach (var target in GetSyncTargets(provider))
                 {
-                    maxBitrate = Convert.ToInt32(maxBitrate.Value * .75);
+                    if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return GetSyncJobOptions(provider, target, profile, quality);
+                    }
                 }
-                else if (job.Quality == SyncQuality.Low)
+            }
+
+            return GetDefaultSyncJobOptions(profile, quality);
+        }
+
+        private SyncJobOptions GetSyncJobOptions(ISyncProvider provider, SyncTarget target, string profile, string quality)
+        {
+            var hasProfile = provider as IHasSyncQuality;
+
+            if (hasProfile != null)
+            {
+                return hasProfile.GetSyncJobOptions(target, profile, quality);
+            }
+
+            return GetDefaultSyncJobOptions(profile, quality);
+        }
+
+        private SyncJobOptions GetDefaultSyncJobOptions(string profile, string quality)
+        {
+            var supportsAc3 = string.Equals(profile, "general", StringComparison.OrdinalIgnoreCase);
+
+            var deviceProfile = new CloudSyncProfile(supportsAc3, false);
+            deviceProfile.MaxStaticBitrate = SyncHelper.AdjustBitrate(deviceProfile.MaxStaticBitrate, quality);
+
+            return new SyncJobOptions
+            {
+                DeviceProfile = deviceProfile,
+                IsConverting = IsConverting(profile, quality)
+            };
+        }
+
+        private bool IsConverting(string profile, string quality)
+        {
+            return !string.Equals(profile, "original", StringComparison.OrdinalIgnoreCase);
+        }
+
+        public IEnumerable<SyncQualityOption> GetQualityOptions(string targetId)
+        {
+            foreach (var provider in _providers)
+            {
+                foreach (var target in GetSyncTargets(provider))
                 {
-                    maxBitrate = Convert.ToInt32(maxBitrate.Value * .5);
+                    if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return GetQualityOptions(provider, target);
+                    }
                 }
             }
 
-            return new VideoOptions
+            return new List<SyncQualityOption>();
+        }
+
+        private IEnumerable<SyncQualityOption> GetQualityOptions(ISyncProvider provider, SyncTarget target)
+        {
+            var hasQuality = provider as IHasSyncQuality;
+            if (hasQuality != null)
+            {
+                return hasQuality.GetQualityOptions(target);
+            }
+
+            // Default options for providers that don't override
+            return new List<SyncQualityOption>
             {
-                Profile = profile,
-                MaxBitrate = maxBitrate
+                new SyncQualityOption
+                {
+                    Name = "High",
+                    Id = "high",
+                    IsDefault = true
+                },
+                new SyncQualityOption
+                {
+                    Name = "Medium",
+                    Id = "medium"
+                },
+                new SyncQualityOption
+                {
+                    Name = "Low",
+                    Id = "low"
+                },
+                new SyncQualityOption
+                {
+                    Name = "Custom",
+                    Id = "custom"
+                }
             };
         }
+
+        public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId)
+        {
+            foreach (var provider in _providers)
+            {
+                foreach (var target in GetSyncTargets(provider))
+                {
+                    if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase))
+                    {
+                        return GetProfileOptions(provider, target);
+                    }
+                }
+            }
+
+            return new List<SyncProfileOption>();
+        }
+
+        private IEnumerable<SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target)
+        {
+            var hasQuality = provider as IHasSyncQuality;
+            if (hasQuality != null)
+            {
+                return hasQuality.GetProfileOptions(target);
+            }
+
+            var list = new List<SyncProfileOption>();
+
+            list.Add(new SyncProfileOption
+            {
+                Name = "Original",
+                Id = "Original",
+                Description = "Syncs original files as-is.",
+                EnableQualityOptions = false
+            });
+
+            list.Add(new SyncProfileOption
+            {
+                Name = "Baseline",
+                Id = "baseline",
+                Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio."
+            });
+
+            list.Add(new SyncProfileOption
+            {
+                Name = "General",
+                Id = "general",
+                Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.",
+                IsDefault = true
+            });
+
+            return list;
+        }
     }
 }
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
index 05d804cbb6..5ad351af52 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs
@@ -50,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             string[] queries = {
 
-                                "create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Quality TEXT NOT NULL, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)",
+                                "create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Profile TEXT, Quality TEXT, Bitrate INT, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)",
                                 "create index if not exists idx_SyncJobs on SyncJobs(Id)",
 
                                 "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, ItemName TEXT, MediaSourceId TEXT, JobId TEXT, TemporaryPath TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT, AdditionalFiles TEXT, MediaSource TEXT, IsMarkedForRemoval BIT, JobItemIndex INT)",
@@ -64,6 +64,9 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             _connection.RunQueries(queries, _logger);
 
+            _connection.AddColumn(_logger, "SyncJobs", "Profile", "TEXT");
+            _connection.AddColumn(_logger, "SyncJobs", "Bitrate", "INT");
+         
             PrepareStatements();
         }
 
@@ -81,12 +84,14 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             // _insertJobCommand
             _insertJobCommand = _connection.CreateCommand();
-            _insertJobCommand.CommandText = "insert into SyncJobs (Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Quality, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
+            _insertJobCommand.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)";
 
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@Id");
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@TargetId");
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@Name");
+            _insertJobCommand.Parameters.Add(_insertJobCommand, "@Profile");
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@Quality");
+            _insertJobCommand.Parameters.Add(_insertJobCommand, "@Bitrate");
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@Status");
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@Progress");
             _insertJobCommand.Parameters.Add(_insertJobCommand, "@UserId");
@@ -102,12 +107,14 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             // _updateJobCommand
             _updateJobCommand = _connection.CreateCommand();
-            _updateJobCommand.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Quality=@Quality,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@ID";
+            _updateJobCommand.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@ID";
 
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@Id");
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@TargetId");
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@Name");
+            _updateJobCommand.Parameters.Add(_updateJobCommand, "@Profile");
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@Quality");
+            _updateJobCommand.Parameters.Add(_updateJobCommand, "@Bitrate");
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@Status");
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@Progress");
             _updateJobCommand.Parameters.Add(_updateJobCommand, "@UserId");
@@ -162,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Sync
             _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobItemIndex");
         }
 
-        private const string BaseJobSelectText = "select Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs";
+        private const string BaseJobSelectText = "select Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs";
         private const string BaseJobItemSelectText = "select Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex from SyncJobItems";
 
         public SyncJob GetJob(string id)
@@ -210,54 +217,64 @@ namespace MediaBrowser.Server.Implementations.Sync
 
             if (!reader.IsDBNull(3))
             {
-                info.Quality = (SyncQuality)Enum.Parse(typeof(SyncQuality), reader.GetString(3), true);
+                info.Profile = reader.GetString(3);
             }
 
             if (!reader.IsDBNull(4))
             {
-                info.Status = (SyncJobStatus)Enum.Parse(typeof(SyncJobStatus), reader.GetString(4), true);
+                info.Quality = reader.GetString(4);
             }
 
             if (!reader.IsDBNull(5))
             {
-                info.Progress = reader.GetDouble(5);
+                info.Bitrate = reader.GetInt32(5);
             }
 
             if (!reader.IsDBNull(6))
             {
-                info.UserId = reader.GetString(6);
+                info.Status = (SyncJobStatus)Enum.Parse(typeof(SyncJobStatus), reader.GetString(6), true);
             }
 
             if (!reader.IsDBNull(7))
             {
-                info.RequestedItemIds = reader.GetString(7).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
+                info.Progress = reader.GetDouble(7);
             }
 
             if (!reader.IsDBNull(8))
             {
-                info.Category = (SyncCategory)Enum.Parse(typeof(SyncCategory), reader.GetString(8), true);
+                info.UserId = reader.GetString(8);
             }
 
             if (!reader.IsDBNull(9))
             {
-                info.ParentId = reader.GetString(9);
+                info.RequestedItemIds = reader.GetString(9).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
             }
 
             if (!reader.IsDBNull(10))
             {
-                info.UnwatchedOnly = reader.GetBoolean(10);
+                info.Category = (SyncCategory)Enum.Parse(typeof(SyncCategory), reader.GetString(10), true);
             }
 
             if (!reader.IsDBNull(11))
             {
-                info.ItemLimit = reader.GetInt32(11);
+                info.ParentId = reader.GetString(11);
             }
 
-            info.SyncNewContent = reader.GetBoolean(12);
+            if (!reader.IsDBNull(12))
+            {
+                info.UnwatchedOnly = reader.GetBoolean(12);
+            }
+
+            if (!reader.IsDBNull(13))
+            {
+                info.ItemLimit = reader.GetInt32(13);
+            }
 
-            info.DateCreated = reader.GetDateTime(13).ToUniversalTime();
-            info.DateLastModified = reader.GetDateTime(14).ToUniversalTime();
-            info.ItemCount = reader.GetInt32(15);
+            info.SyncNewContent = reader.GetBoolean(14);
+
+            info.DateCreated = reader.GetDateTime(15).ToUniversalTime();
+            info.DateLastModified = reader.GetDateTime(16).ToUniversalTime();
+            info.ItemCount = reader.GetInt32(17);
 
             return info;
         }
@@ -294,7 +311,9 @@ namespace MediaBrowser.Server.Implementations.Sync
                 cmd.GetParameter(index++).Value = new Guid(job.Id);
                 cmd.GetParameter(index++).Value = job.TargetId;
                 cmd.GetParameter(index++).Value = job.Name;
+                cmd.GetParameter(index++).Value = job.Profile;
                 cmd.GetParameter(index++).Value = job.Quality;
+                cmd.GetParameter(index++).Value = job.Bitrate;
                 cmd.GetParameter(index++).Value = job.Status.ToString();
                 cmd.GetParameter(index++).Value = job.Progress;
                 cmd.GetParameter(index++).Value = job.UserId;
@@ -421,7 +440,7 @@ namespace MediaBrowser.Server.Implementations.Sync
 
                 var whereClauses = new List<string>();
 
-                if (query.Statuses.Count > 0)
+                if (query.Statuses.Length > 0)
                 {
                     var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
 
@@ -430,6 +449,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                 if (!string.IsNullOrWhiteSpace(query.TargetId))
                 {
                     whereClauses.Add("TargetId=@TargetId");
+                    cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
                 }
                 if (!string.IsNullOrWhiteSpace(query.UserId))
                 {
@@ -442,6 +462,8 @@ namespace MediaBrowser.Server.Implementations.Sync
                     cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value;
                 }
 
+                cmd.CommandText += " mainTable";
+
                 var whereTextWithoutPaging = whereClauses.Count == 0 ?
                     string.Empty :
                     " where " + string.Join(" AND ", whereClauses.ToArray());
@@ -449,7 +471,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                 var startIndex = query.StartIndex ?? 0;
                 if (startIndex > 0)
                 {
-                    whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=@TargetId) DESC, DateLastModified DESC LIMIT {0})",
+                    whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})",
                         startIndex.ToString(_usCulture)));
                 }
 
@@ -458,8 +480,7 @@ namespace MediaBrowser.Server.Implementations.Sync
                     cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray());
                 }
 
-                cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=@TargetId) DESC, DateLastModified DESC";
-                cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
+                cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC";
 
                 if (query.Limit.HasValue)
                 {
@@ -539,13 +560,18 @@ namespace MediaBrowser.Server.Implementations.Sync
                     whereClauses.Add("JobId=@JobId");
                     cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId;
                 }
+                if (!string.IsNullOrWhiteSpace(query.ItemId))
+                {
+                    whereClauses.Add("ItemId=@ItemId");
+                    cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId;
+                }
                 if (!string.IsNullOrWhiteSpace(query.TargetId))
                 {
                     whereClauses.Add("TargetId=@TargetId");
                     cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId;
                 }
 
-                if (query.Statuses.Count > 0)
+                if (query.Statuses.Length > 0)
                 {
                     var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray());
 
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
new file mode 100644
index 0000000000..893b16b140
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
@@ -0,0 +1,68 @@
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Sync;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public class SyncedMediaSourceProvider : IMediaSourceProvider
+    {
+        private readonly SyncManager _syncManager;
+        private readonly IServerApplicationHost _appHost;
+
+        public SyncedMediaSourceProvider(ISyncManager syncManager, IServerApplicationHost appHost)
+        {
+            _appHost = appHost;
+            _syncManager = (SyncManager)syncManager;
+        }
+
+        public async Task<IEnumerable<MediaSourceInfo>> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
+        {
+            var jobItemResult = _syncManager.GetJobItems(new SyncJobItemQuery
+            {
+                AddMetadata = false,
+                Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Synced },
+                ItemId = item.Id.ToString("N")
+            });
+
+            var list = new List<MediaSourceInfo>();
+
+            if (jobItemResult.Items.Length > 0)
+            {
+                var targets = _syncManager.ServerSyncProviders
+                    .SelectMany(i => i.GetAllSyncTargets().Select(t => new Tuple<IServerSyncProvider, SyncTarget>(i, t)))
+                    .ToList();
+
+                var serverId = _appHost.SystemId;
+
+                foreach (var jobItem in jobItemResult.Items)
+                {
+                    var targetTuple = targets.FirstOrDefault(i => string.Equals(i.Item2.Id, jobItem.TargetId, StringComparison.OrdinalIgnoreCase));
+
+                    if (targetTuple != null)
+                    {
+                        var syncTarget = targetTuple.Item2;
+
+                        var dataProvider = _syncManager.GetDataProvider(targetTuple.Item1, syncTarget);
+
+                        var localItems = await dataProvider.GetCachedItems(syncTarget, serverId, item.Id.ToString("N")).ConfigureAwait(false);
+
+                        foreach (var localItem in localItems)
+                        {
+                            list.AddRange(localItem.Item.MediaSources);
+                        }
+                    }
+                }
+            }
+
+            return list;
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
new file mode 100644
index 0000000000..ca9d96c12f
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs
@@ -0,0 +1,243 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Sync;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Serialization;
+using MediaBrowser.Model.Sync;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Sync
+{
+    public class TargetDataProvider : ISyncDataProvider
+    {
+        private readonly SyncTarget _target;
+        private readonly IServerSyncProvider _provider;
+
+        private readonly SemaphoreSlim _dataLock = new SemaphoreSlim(1, 1);
+        private List<LocalItem> _items;
+
+        private readonly ILogger _logger;
+        private readonly IJsonSerializer _json;
+        private readonly IFileSystem _fileSystem;
+        private readonly IApplicationPaths _appPaths;
+        private readonly string _serverId;
+
+        private readonly SemaphoreSlim _cacheFileLock = new SemaphoreSlim(1, 1);
+
+        public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, string serverId, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths)
+        {
+            _logger = logger;
+            _json = json;
+            _provider = provider;
+            _target = target;
+            _fileSystem = fileSystem;
+            _appPaths = appPaths;
+            _serverId = serverId;
+        }
+
+        private string GetCachePath()
+        {
+            return Path.Combine(_appPaths.DataPath, "sync", _target.Id.GetMD5().ToString("N") + ".json");
+        }
+
+        private string GetRemotePath()
+        {
+            var parts = new List<string>
+            {
+                _serverId,
+                "data.json"
+            };
+
+            return _provider.GetFullPath(parts, _target);
+        }
+
+        private async Task CacheData(Stream stream)
+        {
+            var cachePath = GetCachePath();
+
+            await _cacheFileLock.WaitAsync().ConfigureAwait(false);
+
+            try
+            {
+                Directory.CreateDirectory(Path.GetDirectoryName(cachePath));
+                using (var fileStream = _fileSystem.GetFileStream(cachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
+                {
+                    await stream.CopyToAsync(fileStream).ConfigureAwait(false);
+                }
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error saving sync data to {0}", ex, cachePath);
+            }
+            finally
+            {
+                _cacheFileLock.Release();
+            }
+        }
+
+        private async Task EnsureData(CancellationToken cancellationToken)
+        {
+            if (_items == null)
+            {
+                try
+                {
+                    using (var stream = await _provider.GetFile(GetRemotePath(), _target, new Progress<double>(), cancellationToken))
+                    {
+                        _items = _json.DeserializeFromStream<List<LocalItem>>(stream);
+                    }
+                }
+                catch (FileNotFoundException)
+                {
+                    _items = new List<LocalItem>();
+                }
+                catch (DirectoryNotFoundException)
+                {
+                    _items = new List<LocalItem>();
+                }
+
+                using (var memoryStream = new MemoryStream())
+                {
+                    _json.SerializeToStream(_items, memoryStream);
+                    
+                    // Now cache it
+                    memoryStream.Position = 0;
+                    await CacheData(memoryStream).ConfigureAwait(false);
+                }
+            }
+        }
+
+        private async Task SaveData(CancellationToken cancellationToken)
+        {
+            using (var stream = new MemoryStream())
+            {
+                _json.SerializeToStream(_items, stream);
+
+                // Save to sync provider
+                stream.Position = 0;
+                await _provider.SendFile(stream, GetRemotePath(), _target, new Progress<double>(), cancellationToken).ConfigureAwait(false);
+
+                // Now cache it
+                stream.Position = 0;
+                await CacheData(stream).ConfigureAwait(false);
+            }
+        }
+
+        private async Task<T> GetData<T>(Func<List<LocalItem>, T> dataFactory)
+        {
+            await _dataLock.WaitAsync().ConfigureAwait(false);
+
+            try
+            {
+                await EnsureData(CancellationToken.None).ConfigureAwait(false);
+
+                return dataFactory(_items);
+            }
+            finally
+            {
+                _dataLock.Release();
+            }
+        }
+
+        private async Task UpdateData(Func<List<LocalItem>, List<LocalItem>> action)
+        {
+            await _dataLock.WaitAsync().ConfigureAwait(false);
+
+            try
+            {
+                await EnsureData(CancellationToken.None).ConfigureAwait(false);
+
+                _items = action(_items);
+
+                await SaveData(CancellationToken.None).ConfigureAwait(false);
+            }
+            finally
+            {
+                _dataLock.Release();
+            }
+        }
+
+        public Task<List<string>> GetServerItemIds(SyncTarget target, string serverId)
+        {
+            return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.ItemId).ToList());
+        }
+
+        public Task AddOrUpdate(SyncTarget target, LocalItem item)
+        {
+            return UpdateData(items =>
+            {
+                var list = items.Where(i => !string.Equals(i.Id, item.Id, StringComparison.OrdinalIgnoreCase))
+                    .ToList();
+
+                list.Add(item);
+
+                return list;
+            });
+        }
+
+        public Task Delete(SyncTarget target, string id)
+        {
+            return UpdateData(items => items.Where(i => !string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)).ToList());
+        }
+
+        public Task<LocalItem> Get(SyncTarget target, string id)
+        {
+            return GetData(items => items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase)));
+        }
+
+        private async Task<List<LocalItem>> GetCachedData()
+        {
+            if (_items == null)
+            {
+                await _cacheFileLock.WaitAsync().ConfigureAwait(false);
+
+                try
+                {
+                    if (_items == null)
+                    {
+                        try
+                        {
+                            _items = _json.DeserializeFromFile<List<LocalItem>>(GetCachePath());
+                        }
+                        catch (FileNotFoundException)
+                        {
+                            _items = new List<LocalItem>();
+                        }
+                        catch (DirectoryNotFoundException)
+                        {
+                            _items = new List<LocalItem>();
+                        }
+                    }
+                }
+                finally
+                {
+                    _cacheFileLock.Release();
+                }
+            }
+
+            return _items.ToList();
+        }
+
+        public async Task<List<string>> GetCachedServerItemIds(SyncTarget target, string serverId)
+        {
+            var items = await GetCachedData().ConfigureAwait(false);
+
+            return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase))
+                    .Select(i => i.ItemId)
+                    .ToList();
+        }
+
+        public async Task<List<LocalItem>> GetCachedItems(SyncTarget target, string serverId, string itemId)
+        {
+            var items = await GetCachedData().ConfigureAwait(false);
+
+            return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase))
+                    .ToList();
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
new file mode 100644
index 0000000000..b98dd2c49b
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
@@ -0,0 +1,292 @@
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Server.Implementations.Photos;
+using MoreLinq;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.UserViews
+{
+    public class DynamicImageProvider : BaseDynamicImageProvider<UserView>, IPreRefreshProvider
+    {
+        private readonly IUserManager _userManager;
+        private readonly ILibraryManager _libraryManager;
+
+        public DynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IUserManager userManager, ILibraryManager libraryManager)
+            : base(fileSystem, providerManager, applicationPaths)
+        {
+            _userManager = userManager;
+            _libraryManager = libraryManager;
+        }
+
+        public override IEnumerable<ImageType> GetSupportedImages(IHasImages item)
+        {
+            var view = (UserView)item;
+            if (IsUsingCollectionStrip(view))
+            {
+                return new List<ImageType>
+                {
+                    ImageType.Primary
+                };
+            }
+
+            return new List<ImageType>
+            {
+                ImageType.Primary,
+                ImageType.Thumb
+            };
+        }
+
+        protected override async Task<List<BaseItem>> GetItemsWithImages(IHasImages item)
+        {
+            var view = (UserView)item;
+
+            if (!view.UserId.HasValue)
+            {
+                return new List<BaseItem>();
+            }
+
+            if (string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+            {
+                return new List<BaseItem>();
+            }
+
+            if (string.Equals(view.ViewType, SpecialFolder.GameGenre, StringComparison.OrdinalIgnoreCase))
+            {
+                var list = new List<BaseItem>();
+
+                var genre = _libraryManager.GetGameGenre(view.Name);
+
+                if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
+                {
+                    list.Add(genre);
+                }
+                return list;
+            }
+            if (string.Equals(view.ViewType, SpecialFolder.MusicGenre, StringComparison.OrdinalIgnoreCase))
+            {
+                var list = new List<BaseItem>();
+
+                var genre = _libraryManager.GetMusicGenre(view.Name);
+
+                if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
+                {
+                    list.Add(genre);
+                }
+                return list;
+            }
+            if (string.Equals(view.ViewType, SpecialFolder.MovieGenre, StringComparison.OrdinalIgnoreCase) ||
+                string.Equals(view.ViewType, SpecialFolder.TvGenre, StringComparison.OrdinalIgnoreCase))
+            {
+                var list = new List<BaseItem>();
+
+                var genre = _libraryManager.GetGenre(view.Name);
+
+                if (genre.HasImage(ImageType.Primary) || genre.HasImage(ImageType.Thumb))
+                {
+                    list.Add(genre);
+                }
+                return list;
+            }
+
+            var isUsingCollectionStrip = IsUsingCollectionStrip(view);
+            var recursive = isUsingCollectionStrip && !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+
+            var result = await view.GetItems(new InternalItemsQuery
+            {
+                User = _userManager.GetUserById(view.UserId.Value),
+                CollapseBoxSetItems = false,
+                Recursive = recursive,
+                ExcludeItemTypes = new[] { "UserView", "CollectionFolder" }
+
+            }).ConfigureAwait(false);
+
+            var items = result.Items.Select(i =>
+            {
+                var episode = i as Episode;
+                if (episode != null)
+                {
+                    var series = episode.Series;
+                    if (series != null)
+                    {
+                        return series;
+                    }
+                    var episodeSeason = episode.Season;
+                    if (episodeSeason != null)
+                    {
+                        return episodeSeason;
+                    }
+
+                    return episode;
+                }
+
+                var season = i as Season;
+                if (season != null)
+                {
+                    var series = season.Series;
+                    if (series != null)
+                    {
+                        return series;
+                    }
+
+                    return season;
+                }
+
+                var audio = i as Audio;
+                if (audio != null)
+                {
+                    var album = audio.FindParent<MusicAlbum>();
+                    if (album != null && album.HasImage(ImageType.Primary))
+                    {
+                        return album;
+                    }
+                }
+
+                return i;
+
+            }).DistinctBy(i => i.Id);
+
+            if (isUsingCollectionStrip)
+            {
+                return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8);
+            }
+
+            return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary)).ToList());
+        }
+
+        public override bool Supports(IHasImages item)
+        {
+            var view = item as UserView;
+
+            if (view != null && view.UserId.HasValue)
+            {
+                var supported = new[]
+                {
+                    SpecialFolder.TvFavoriteEpisodes,
+                    SpecialFolder.TvFavoriteSeries,
+                    SpecialFolder.TvGenres,
+                    SpecialFolder.TvGenre,
+                    SpecialFolder.TvLatest,
+                    SpecialFolder.TvNextUp,
+                    SpecialFolder.TvResume,
+                    SpecialFolder.TvShowSeries,
+
+                    SpecialFolder.MovieCollections,
+                    SpecialFolder.MovieFavorites,
+                    SpecialFolder.MovieGenres,
+                    SpecialFolder.MovieGenre,
+                    SpecialFolder.MovieLatest,
+                    SpecialFolder.MovieMovies,
+                    SpecialFolder.MovieResume,
+
+                    SpecialFolder.GameFavorites,
+                    SpecialFolder.GameGenres,
+                    SpecialFolder.GameGenre,
+                    SpecialFolder.GameSystems,
+                    SpecialFolder.LatestGames,
+                    SpecialFolder.RecentlyPlayedGames,
+
+                    SpecialFolder.MusicArtists,
+                    SpecialFolder.MusicAlbumArtists,
+                    SpecialFolder.MusicAlbums,
+                    SpecialFolder.MusicGenres,
+                    SpecialFolder.MusicGenre,
+                    SpecialFolder.MusicLatest,
+                    SpecialFolder.MusicSongs,
+                    SpecialFolder.MusicFavorites,
+                    SpecialFolder.MusicFavoriteArtists,
+                    SpecialFolder.MusicFavoriteAlbums,
+                    SpecialFolder.MusicFavoriteSongs
+                };
+
+                return (IsUsingCollectionStrip(view) || supported.Contains(view.ViewType, StringComparer.OrdinalIgnoreCase)) &&
+                    _userManager.GetUserById(view.UserId.Value) != null;
+            }
+
+            return false;
+        }
+
+        private bool IsUsingCollectionStrip(UserView view)
+        {
+            string[] collectionStripViewTypes =
+            {
+                CollectionType.Movies,
+                CollectionType.TvShows,
+                CollectionType.Games,
+                CollectionType.Music,
+                CollectionType.BoxSets,
+                CollectionType.Playlists,
+                CollectionType.Channels,
+                CollectionType.LiveTv,
+                CollectionType.Books,
+                CollectionType.Photos,
+                CollectionType.HomeVideos,
+                CollectionType.MusicVideos,
+                string.Empty
+            };
+
+            return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
+        }
+
+        protected override Task<Stream> CreateImageAsync(IHasImages item, List<BaseItem> itemsWithImages, ImageType imageType, int imageIndex)
+        {
+            var view = (UserView)item;
+            if (imageType == ImageType.Primary && IsUsingCollectionStrip(view))
+            {
+                if (itemsWithImages.Count == 0 && !string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+                {
+                    return null;
+                }
+
+                var stream = new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(itemsWithImages, view.ViewType), item.Name, 960, 540);
+                return Task.FromResult(stream);
+            }
+
+            return base.CreateImageAsync(item, itemsWithImages, imageType, imageIndex);
+        }
+
+        private IEnumerable<String> GetStripCollageImagePaths(IEnumerable<BaseItem> items, string viewType)
+        {
+            if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+            {
+                var list = new List<string>();
+                for (int i = 1; i <= 8; i++)
+                {
+                    list.Add(ExtractLiveTvResource(i.ToString(CultureInfo.InvariantCulture), ApplicationPaths));
+                }
+                return list;
+            }
+
+            return items
+                .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
+                .Where(i => !string.IsNullOrWhiteSpace(i));
+        }
+
+        private string ExtractLiveTvResource(string name, IApplicationPaths paths)
+        {
+            var namespacePath = GetType().Namespace + ".livetv." + name + ".jpg";
+            var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".jpg");
+            Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
+
+            using (var stream = GetType().Assembly.GetManifestResourceStream(namespacePath))
+            {
+                using (var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+                {
+                    stream.CopyTo(fileStream);
+                }
+            }
+
+            return tempPath;
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs b/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs
new file mode 100644
index 0000000000..2f2d9860c1
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs
@@ -0,0 +1,180 @@
+using ImageMagickSharp;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Server.Implementations.Drawing;
+using MediaBrowser.Server.Implementations.Photos;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Server.Implementations.UserViews
+{
+    public class StripCollageBuilder
+    {
+        private readonly IApplicationPaths _appPaths;
+
+        public StripCollageBuilder(IApplicationPaths appPaths)
+        {
+            _appPaths = appPaths;
+        }
+
+        public Stream BuildThumbCollage(IEnumerable<string> paths, string text, int width, int height)
+        {
+            using (var wand = BuildThumbCollageWandWithText(paths, text, width, height))
+            {
+                return DynamicImageHelpers.GetStream(wand, _appPaths);
+            }
+        }
+
+        private string[] ProjectPaths(IEnumerable<string> paths, int count)
+        {
+            var clone = paths.ToList();
+            var list = new List<string>();
+
+            while (list.Count < count)
+            {
+                foreach (var path in clone)
+                {
+                    list.Add(path);
+
+                    if (list.Count >= count)
+                    {
+                        break;
+                    }
+                }
+            }
+
+            return list.Take(count).ToArray();
+        }
+
+        private MagickWand BuildThumbCollageWandWithText(IEnumerable<string> paths, string text, int width, int height)
+        {
+            var inputPaths = ProjectPaths(paths, 8);
+            using (var wandImages = new MagickWand(inputPaths))
+            {
+                var wand = new MagickWand(width, height);
+                wand.OpenImage("gradient:#111111-#111111");
+                using (var draw = new DrawingWand())
+                {
+                    using (var fcolor = new PixelWand(ColorName.White))
+                    {
+                        draw.FillColor = fcolor;
+                        draw.Font = MontserratLightFont;
+                        draw.FontSize = 50;
+                        draw.FontWeight = FontWeightType.LightStyle;
+                        draw.TextAntialias = true;
+                    }
+
+                    var fontMetrics = wand.QueryFontMetrics(draw, text);
+                    var textContainerY = Convert.ToInt32(height * .165);
+                    wand.CurrentImage.AnnotateImage(draw, (width - fontMetrics.TextWidth) / 2, textContainerY, 0.0, text);
+
+                    var iSlice = Convert.ToInt32(width * .1166666667);
+                    int iTrans = Convert.ToInt32(height * 0.2);
+                    int iHeight = Convert.ToInt32(height * 0.46296296296296296296296296296296);
+                    var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
+
+                    foreach (var element in wandImages.ImageList)
+                    {
+                        int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
+                        element.Gravity = GravityType.CenterGravity;
+                        element.BackgroundColor = new PixelWand("none", 1);
+                        element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
+                        int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+                        element.CropImage(iSlice, iHeight, ix, 0);
+
+                        element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+                    }
+
+                    wandImages.SetFirstIterator();
+                    using (var wandList = wandImages.AppendImages())
+                    {
+                        wandList.CurrentImage.TrimImage(1);
+                        using (var mwr = wandList.CloneMagickWand())
+                        {
+                            mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+                            mwr.CurrentImage.FlipImage();
+
+                            mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+                            mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey70);
+
+                            using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+                            {
+                                mwg.OpenImage("gradient:black-none");
+                                var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+                                mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.DstInCompositeOp, 0, verticalSpacing);
+
+                                wandList.AddImage(mwr);
+                                int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+                                wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * 0.26851851851851851851851851851852));
+                            }
+                        }
+                    }
+                }
+
+                return wand;
+            }
+        }
+
+        private MagickWand BuildThumbCollageWand(IEnumerable<string> paths, int width, int height)
+        {
+            var inputPaths = ProjectPaths(paths, 8);
+            using (var wandImages = new MagickWand(inputPaths))
+            {
+                var wand = new MagickWand(width, height);
+                wand.OpenImage("gradient:#111111-#111111");
+                using (var draw = new DrawingWand())
+                {
+                    var iSlice = Convert.ToInt32(width * .1166666667);
+                    int iTrans = Convert.ToInt32(height * .25);
+                    int iHeight = Convert.ToInt32(height * .6);
+                    var horizontalImagePadding = Convert.ToInt32(width * 0.0125);
+
+                    foreach (var element in wandImages.ImageList)
+                    {
+                        int iWidth = (int)Math.Abs(iHeight * element.Width / element.Height);
+                        element.Gravity = GravityType.CenterGravity;
+                        element.BackgroundColor = ColorName.Black;
+                        element.ResizeImage(iWidth, iHeight, FilterTypes.LanczosFilter);
+                        int ix = (int)Math.Abs((iWidth - iSlice) / 2);
+                        element.CropImage(iSlice, iHeight, ix, 0);
+
+                        element.ExtentImage(iSlice, iHeight, 0 - horizontalImagePadding, 0);
+                    }
+
+                    wandImages.SetFirstIterator();
+                    using (var wandList = wandImages.AppendImages())
+                    {
+                        wandList.CurrentImage.TrimImage(1);
+                        using (var mwr = wandList.CloneMagickWand())
+                        {
+                            mwr.CurrentImage.ResizeImage(wandList.CurrentImage.Width, (wandList.CurrentImage.Height / 2), FilterTypes.LanczosFilter, 1);
+                            mwr.CurrentImage.FlipImage();
+
+                            mwr.CurrentImage.AlphaChannel = AlphaChannelType.DeactivateAlphaChannel;
+                            mwr.CurrentImage.ColorizeImage(ColorName.Black, ColorName.Grey60);
+
+                            using (var mwg = new MagickWand(wandList.CurrentImage.Width, iTrans))
+                            {
+                                mwg.OpenImage("gradient:black-none");
+                                var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111);
+                                mwr.CurrentImage.CompositeImage(mwg, CompositeOperator.CopyOpacityCompositeOp, 0, verticalSpacing);
+
+                                wandList.AddImage(mwr);
+                                int ex = (int)(wand.CurrentImage.Width - mwg.CurrentImage.Width) / 2;
+                                wand.CurrentImage.CompositeImage(wandList.AppendImages(true), CompositeOperator.AtopCompositeOp, ex, Convert.ToInt32(height * .1));
+                            }
+                        }
+                    }
+                }
+
+                return wand;
+            }
+        }
+
+        private string MontserratLightFont
+        {
+            get { return PlayedIndicatorDrawer.ExtractFont("MontserratLight.otf", _appPaths); }
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/1.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/1.jpg
new file mode 100644
index 0000000000..2594b68a42
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/1.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/2.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/2.jpg
new file mode 100644
index 0000000000..e5c87b96b0
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/2.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/3.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/3.jpg
new file mode 100644
index 0000000000..c19f7e6124
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/3.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/4.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/4.jpg
new file mode 100644
index 0000000000..93ee18044f
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/4.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/5.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/5.jpg
new file mode 100644
index 0000000000..4c2cd580d3
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/5.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/6.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/6.jpg
new file mode 100644
index 0000000000..6f496b6acb
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/6.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/7.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/7.jpg
new file mode 100644
index 0000000000..e7dba27601
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/7.jpg differ
diff --git a/MediaBrowser.Server.Implementations/UserViews/livetv/8.jpg b/MediaBrowser.Server.Implementations/UserViews/livetv/8.jpg
new file mode 100644
index 0000000000..c69ba908ce
Binary files /dev/null and b/MediaBrowser.Server.Implementations/UserViews/livetv/8.jpg differ
diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config
index 55023c5650..438ccff92a 100644
--- a/MediaBrowser.Server.Implementations/packages.config
+++ b/MediaBrowser.Server.Implementations/packages.config
@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="ImageMagickSharp" version="1.0.0.11" targetFramework="net45" />
   <package id="MediaBrowser.Naming" version="1.0.0.32" targetFramework="net45" />
   <package id="Mono.Nat" version="1.2.21.0" targetFramework="net45" />
   <package id="morelinq" version="1.1.0" targetFramework="net45" />
   <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
-  <package id="SocketHttpListener" version="1.0.0.1" targetFramework="net45" />
+  <package id="SocketHttpListener" version="1.0.0.3" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/Diagnostics/LinuxProcessManager.cs b/MediaBrowser.Server.Mono/Diagnostics/LinuxProcessManager.cs
new file mode 100644
index 0000000000..a66365212b
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Diagnostics/LinuxProcessManager.cs
@@ -0,0 +1,25 @@
+using MediaBrowser.Controller.Diagnostics;
+using System.Diagnostics;
+
+namespace MediaBrowser.Server.Mono.Diagnostics
+{
+    public class LinuxProcessManager : IProcessManager
+    {
+        public bool SupportsSuspension
+        {
+            get { return true; }
+        }
+
+        public void SuspendProcess(Process process)
+        {
+            // http://jumptuck.com/2011/11/23/quick-tip-pause-process-linux/
+            process.StandardInput.WriteLine("^Z");
+        }
+
+        public void ResumeProcess(Process process)
+        {
+            // http://jumptuck.com/2011/11/23/quick-tip-pause-process-linux/
+            process.StandardInput.WriteLine("fg");
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Mono/ImageMagickSharp.dll.config b/MediaBrowser.Server.Mono/ImageMagickSharp.dll.config
new file mode 100644
index 0000000000..ac4918ef2f
--- /dev/null
+++ b/MediaBrowser.Server.Mono/ImageMagickSharp.dll.config
@@ -0,0 +1,4 @@
+<configuration>
+  <dllmap dll="CORE_RL_Wand_.dll" target="libMagickWand-6.Q8.so" os="linux"/>
+  <dllmap dll="CORE_RL_Wand_.dll" target="./MediaInfo/osx/libmediainfo.dylib" os="osx"/>
+</configuration>
\ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/Imazen.WebP.dll.config b/MediaBrowser.Server.Mono/Imazen.WebP.dll.config
deleted file mode 100644
index a7a2c13978..0000000000
--- a/MediaBrowser.Server.Mono/Imazen.WebP.dll.config
+++ /dev/null
@@ -1,4 +0,0 @@
-<configuration>
-  <dllmap dll="libwebp" target="./libwebp/osx/libwebp.5.dylib" os="osx"/>
-  <dllmap dll="libwebp" target="libwebp.so.5" os="linux"/>
-</configuration>
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index 232caba4ff..8f552ee362 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -74,6 +74,7 @@
     <Compile Include="..\SharedVersion.cs">
       <Link>Properties\SharedVersion.cs</Link>
     </Compile>
+    <Compile Include="Diagnostics\LinuxProcessManager.cs" />
     <Compile Include="Native\BaseMonoApp.cs" />
     <Compile Include="Networking\CertificateGenerator.cs" />
     <Compile Include="Program.cs" />
@@ -137,10 +138,6 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <None Include="..\ThirdParty\libwebp\osx\libwebp.5.dylib">
-      <Link>libwebp\osx\libwebp.5.dylib</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
     <None Include="..\ThirdParty\MediaInfo\osx\libmediainfo.dylib">
       <Link>MediaInfo\osx\libmediainfo.dylib</Link>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -154,7 +151,7 @@
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
     <None Include="app.config" />
-    <None Include="Imazen.WebP.dll.config">
+    <None Include="ImageMagickSharp.dll.config">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
     <None Include="MediaBrowser.MediaInfo.dll.config">
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index 1ec0109ad8..139661aa28 100644
--- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
+++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
@@ -1,6 +1,8 @@
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Mono.Diagnostics;
 using MediaBrowser.Server.Mono.Networking;
 using MediaBrowser.Server.Startup.Common;
 using Mono.Unix.Native;
@@ -189,5 +191,16 @@ namespace MediaBrowser.Server.Mono.Native
             public string sysname = string.Empty;
             public string machine = string.Empty;
         }
+
+
+        public IProcessManager GetProcessManager()
+        {
+            if (Environment.OperatingSystem == Startup.Common.OperatingSystem.Linux)
+            {
+                return new LinuxProcessManager();
+            }
+
+            return new ProcessManager();
+        }
     }
 }
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 49399ba4ef..f35317cd2a 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -197,6 +197,7 @@ namespace MediaBrowser.Server.Startup.Common
         private ITVSeriesManager TVSeriesManager { get; set; }
         private ICollectionManager CollectionManager { get; set; }
         private IMediaSourceManager MediaSourceManager { get; set; }
+        private IPlaylistManager PlaylistManager { get; set; }
 
         private readonly StartupOptions _startupOptions;
         private readonly string _remotePackageName;
@@ -380,6 +381,8 @@ namespace MediaBrowser.Server.Startup.Common
 
             RegisterSingleInstance(ServerConfigurationManager);
 
+            RegisterSingleInstance(NativeApp.GetProcessManager());
+
             LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer);
             RegisterSingleInstance(LocalizationManager);
 
@@ -421,7 +424,7 @@ namespace MediaBrowser.Server.Startup.Common
             LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
             RegisterSingleInstance(LibraryMonitor);
 
-            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths);
+            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager);
             RegisterSingleInstance(ProviderManager);
 
             SeriesOrderManager = new SeriesOrderManager();
@@ -439,33 +442,27 @@ namespace MediaBrowser.Server.Startup.Common
             var innerProgress = new ActionableProgress<double>();
             innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
 
-            ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, MediaEncoder);
+            ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer);
             RegisterSingleInstance(ImageProcessor);
 
             TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager);
             RegisterSingleInstance(TVSeriesManager);
 
-            SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager);
+            SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager, UserDataManager, () => MediaSourceManager, JsonSerializer);
             RegisterSingleInstance(SyncManager);
 
-            DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager);
+            DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager);
             RegisterSingleInstance(DtoService);
 
             var encryptionManager = new EncryptionManager();
             RegisterSingleInstance<IEncryptionManager>(encryptionManager);
 
-            ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager);
+            ConnectManager = new ConnectManager(LogManager.GetLogger("Connect"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager);
             RegisterSingleInstance(ConnectManager);
 
-            DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, Logger, FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"));
+            DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager"));
             RegisterSingleInstance(DeviceManager);
 
-            MediaSourceManager = new MediaSourceManager(ItemRepository);
-            RegisterSingleInstance(MediaSourceManager);
-
-            SessionManager = new SessionManager(UserDataManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
-            RegisterSingleInstance(SessionManager);
-
             var newsService = new Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             RegisterSingleInstance<INewsService>(newsService);
 
@@ -474,9 +471,15 @@ namespace MediaBrowser.Server.Startup.Common
 
             progress.Report(15);
 
-            ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, Logger, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
+            ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
             RegisterSingleInstance(ChannelManager);
 
+            MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, ChannelManager, LogManager.GetLogger("MediaSourceManager"));
+            RegisterSingleInstance(MediaSourceManager);
+
+            SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
+            RegisterSingleInstance(SessionManager);
+
             var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
             RegisterSingleInstance<IAppThemeManager>(appThemeManager);
 
@@ -489,16 +492,16 @@ namespace MediaBrowser.Server.Startup.Common
             CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"));
             RegisterSingleInstance(CollectionManager);
 
-            var playlistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager);
-            RegisterSingleInstance<IPlaylistManager>(playlistManager);
+            PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager);
+            RegisterSingleInstance<IPlaylistManager>(PlaylistManager);
 
-            LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer);
+            LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager);
             RegisterSingleInstance(LiveTvManager);
 
-            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, playlistManager, CollectionManager, ServerConfigurationManager);
+            UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, PlaylistManager, CollectionManager, ServerConfigurationManager);
             RegisterSingleInstance(UserViewManager);
 
-            var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager);
+            var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager);
             RegisterSingleInstance<IContentDirectory>(contentDirectory);
 
             var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager);
@@ -571,7 +574,8 @@ namespace MediaBrowser.Server.Startup.Common
                 LibraryManager,
                 ChannelManager,
                 SessionManager,
-                () => SubtitleEncoder);
+                () => SubtitleEncoder,
+                () => MediaSourceManager);
             RegisterSingleInstance(MediaEncoder);
         }
 
@@ -699,6 +703,7 @@ namespace MediaBrowser.Server.Startup.Common
             BaseItem.LiveTvManager = LiveTvManager;
             Folder.UserViewManager = UserViewManager;
             UserView.TVSeriesManager = TVSeriesManager;
+            UserView.PlaylistManager = PlaylistManager;
             BaseItem.CollectionManager = CollectionManager;
             BaseItem.MediaSourceManager = MediaSourceManager;
         }
@@ -752,6 +757,8 @@ namespace MediaBrowser.Server.Startup.Common
 
             ChannelManager.AddParts(GetExports<IChannel>(), GetExports<IChannelFactory>());
 
+            MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
+            
             NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
             SyncManager.AddParts(GetExports<ISyncProvider>());
         }
diff --git a/MediaBrowser.Server.Startup.Common/Diagnostics/ProcessManager.cs b/MediaBrowser.Server.Startup.Common/Diagnostics/ProcessManager.cs
new file mode 100644
index 0000000000..d01756d0e2
--- /dev/null
+++ b/MediaBrowser.Server.Startup.Common/Diagnostics/ProcessManager.cs
@@ -0,0 +1,23 @@
+using MediaBrowser.Controller.Diagnostics;
+using System.Diagnostics;
+
+namespace MediaBrowser.Server.Mono.Diagnostics
+{
+    public class ProcessManager : IProcessManager
+    {
+        public void SuspendProcess(Process process)
+        {
+            process.PriorityClass = ProcessPriorityClass.Idle;
+        }
+
+        public void ResumeProcess(Process process)
+        {
+            process.PriorityClass = ProcessPriorityClass.Normal;
+        }
+
+        public bool SupportsSuspension
+        {
+            get { return true; }
+        }
+    }
+}
diff --git a/MediaBrowser.Server.Startup.Common/INativeApp.cs b/MediaBrowser.Server.Startup.Common/INativeApp.cs
index 2dbd844baa..1c4b5b1d58 100644
--- a/MediaBrowser.Server.Startup.Common/INativeApp.cs
+++ b/MediaBrowser.Server.Startup.Common/INativeApp.cs
@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.Model.Logging;
 using System.Collections.Generic;
 using System.Reflection;
@@ -84,5 +85,11 @@ namespace MediaBrowser.Server.Startup.Common
         /// Prevents the system stand by.
         /// </summary>
         void PreventSystemStandby();
+
+        /// <summary>
+        /// Gets the process manager.
+        /// </summary>
+        /// <returns>IProcessManager.</returns>
+        IProcessManager GetProcessManager();
     }
 }
diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
index 38e07fde49..625b29d369 100644
--- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
+++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj
@@ -56,6 +56,7 @@
     <Compile Include="ApplicationHost.cs" />
     <Compile Include="ApplicationPathHelper.cs" />
     <Compile Include="Browser\BrowserLauncher.cs" />
+    <Compile Include="Diagnostics\ProcessManager.cs" />
     <Compile Include="EntryPoints\KeepServerAwake.cs" />
     <Compile Include="EntryPoints\StartupWizard.cs" />
     <Compile Include="FFMpeg\FFMpegDownloader.cs" />
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index 6e8774eea1..e77af1c6bb 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -40,6 +40,7 @@ namespace MediaBrowser.ServerApplication
 
             var applicationPath = currentProcess.MainModule.FileName;
 
+            //Wand.SetMagickCoderModulePath(Path.Combine(Path.GetDirectoryName(applicationPath), "ImageMagickCoders", "x86"));
             var appPaths = CreateApplicationPaths(applicationPath, _isRunningAsService);
 
             var logManager = new NlogManager(appPaths.LogDirectoryPath, "server");
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 8df2d3ab06..888b41b212 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -60,6 +60,10 @@
     <Prefer32Bit>true</Prefer32Bit>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="ImageMagickSharp, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\ImageMagickSharp.1.0.0.11\lib\net45\ImageMagickSharp.dll</HintPath>
+    </Reference>
     <Reference Include="MediaBrowser.IsoMounter">
       <HintPath>..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll</HintPath>
     </Reference>
@@ -109,6 +113,7 @@
     <Compile Include="Native\Standby.cs" />
     <Compile Include="Native\ServerAuthorization.cs" />
     <Compile Include="Native\WindowsApp.cs" />
+    <Compile Include="Native\WindowsProcessManager.cs" />
     <Compile Include="Networking\CertificateGenerator.cs" />
     <Compile Include="Networking\NativeMethods.cs" />
     <Compile Include="Networking\NetworkManager.cs" />
@@ -167,14 +172,235 @@
       <Link>x86\SQLite.Interop.dll</Link>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="..\ThirdParty\libwebp\windows\x86\libwebp.dll">
-      <Link>libwebp.dll</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="..\ThirdParty\MediaInfo\windows\x86\MediaInfo.dll">
       <Link>MediaInfo.dll</Link>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="CORE_RL_bzlib_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_cairo_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_exr_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_glib_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_jbig_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_jp2_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_jpeg_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_lcms_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_librsvg_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_libxml_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_lqr_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_Magick++_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_magick_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_openjpeg_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_pango_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_png_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_tiff_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_ttf_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_wand_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_webp_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="CORE_RL_zlib_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_bgr_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_bmp_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_caption_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_clipboard_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_clip_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_cmyk_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_cut_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_dib_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_emf_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_gif_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_gradient_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_gray_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_hdr_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_histogram_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_html_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_icon_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_info_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_jpeg_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_json_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_label_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_magick_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_map_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_mask_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_matte_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_mat_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_meta_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_miff_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_mono_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_mpeg_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_null_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_pattern_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_pdf_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_png_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_preview_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_ps2_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_ps3_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_psd_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_ps_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_raw_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_rgb_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_screenshot_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_thumbnail_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_tiff_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_tile_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_ttf_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_txt_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_url_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_uyvy_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_wbmp_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_webp_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_wmf_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_xc_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_xps_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="IM_MOD_RL_yuv_.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="Resources\Images\Icon.ico" />
     <Content Include="Resources\Images\mb3logo800.png" />
   </ItemGroup>
@@ -232,6 +458,7 @@
       <Name>MediaBrowser.XbmcMetadata</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PostBuildEvent>
@@ -245,4 +472,11 @@
   </Target>
   -->
   <Import Project="..\packages\System.Data.SQLite.Core.1.0.94.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.94.0\build\net45\System.Data.SQLite.Core.targets')" />
+  <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
+  </Target>
 </Project>
\ No newline at end of file
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index 476fb58b9d..74abcb36c2 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
@@ -1,7 +1,9 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Diagnostics;
 using MediaBrowser.IsoMounter;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Server.Mono.Diagnostics;
 using MediaBrowser.Server.Startup.Common;
 using MediaBrowser.ServerApplication.Networking;
 using System.Collections.Generic;
@@ -109,5 +111,10 @@ namespace MediaBrowser.ServerApplication.Native
         {
             Standby.PreventSystemStandby();
         }
+
+        public IProcessManager GetProcessManager()
+        {
+            return new WindowsProcessManager();
+        }
     }
 }
diff --git a/MediaBrowser.ServerApplication/Native/WindowsProcessManager.cs b/MediaBrowser.ServerApplication/Native/WindowsProcessManager.cs
new file mode 100644
index 0000000000..a88f5c1e50
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Native/WindowsProcessManager.cs
@@ -0,0 +1,83 @@
+using MediaBrowser.Controller.Diagnostics;
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+    public class WindowsProcessManager : IProcessManager
+    {
+        public void SuspendProcess(Process process)
+        {
+            process.Suspend();
+        }
+
+        public void ResumeProcess(Process process)
+        {
+            process.Resume();
+        }
+
+        public bool SupportsSuspension
+        {
+            get { return true; }
+        }
+    }
+
+    public static class ProcessExtension
+    {
+        [DllImport("kernel32.dll")]
+        static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
+        [DllImport("kernel32.dll")]
+        static extern uint SuspendThread(IntPtr hThread);
+        [DllImport("kernel32.dll")]
+        static extern int ResumeThread(IntPtr hThread);
+        [DllImport("kernel32.dll")]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool CloseHandle(IntPtr hThread);
+
+        public static void Suspend(this Process process)
+        {
+            foreach (ProcessThread thread in process.Threads)
+            {
+                var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
+                if (pOpenThread == IntPtr.Zero)
+                {
+                    break;
+                }
+                SuspendThread(pOpenThread);
+                CloseHandle(pOpenThread);
+            }
+        }
+        public static void Resume(this Process process)
+        {
+            foreach (ProcessThread thread in process.Threads)
+            {
+                var pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)thread.Id);
+                if (pOpenThread == IntPtr.Zero)
+                {
+                    break;
+                }
+                ResumeThread(pOpenThread);
+                CloseHandle(pOpenThread);
+            }
+        }
+        public static void Print(this Process process)
+        {
+            Console.WriteLine("{0,8}    {1}", process.Id, process.ProcessName);
+        }
+    }
+
+    [Flags]
+    public enum ThreadAccess : int
+    {
+        TERMINATE = (0x0001),
+        SUSPEND_RESUME = (0x0002),
+        GET_CONTEXT = (0x0008),
+        SET_CONTEXT = (0x0010),
+        SET_INFORMATION = (0x0020),
+        QUERY_INFORMATION = (0x0040),
+        SET_THREAD_TOKEN = (0x0080),
+        IMPERSONATE = (0x0100),
+        DIRECT_IMPERSONATION = (0x0200)
+    }
+}
diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config
index db85244636..f429269b3f 100644
--- a/MediaBrowser.ServerApplication/packages.config
+++ b/MediaBrowser.ServerApplication/packages.config
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="ImageMagickSharp" version="1.0.0.11" targetFramework="net45" />
   <package id="MediaBrowser.IsoMounting" version="3.0.69" targetFramework="net45" />
   <package id="System.Data.SQLite.Core" version="1.0.94.0" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/MediaBrowser.WebDashboard/Api/ConfigurationPageInfo.cs b/MediaBrowser.WebDashboard/Api/ConfigurationPageInfo.cs
index 480c11b503..16aa14cb71 100644
--- a/MediaBrowser.WebDashboard/Api/ConfigurationPageInfo.cs
+++ b/MediaBrowser.WebDashboard/Api/ConfigurationPageInfo.cs
@@ -26,7 +26,9 @@ namespace MediaBrowser.WebDashboard.Api
         {
             Name = page.Name;
             ConfigurationPageType = page.ConfigurationPageType;
-            PluginId = page.Plugin.Id.ToString("N");
+
+            // Don't use "N" because it needs to match Plugin.Id
+            PluginId = page.Plugin.Id.ToString();
         }
     }
 }
diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
index 1e188ceae0..a93cccfbcf 100644
--- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs
+++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs
@@ -366,6 +366,7 @@ namespace MediaBrowser.WebDashboard.Api
                                 "backdrops.js",
                                 "sync.js",
                                 "syncjob.js",
+                                "syncservices.js",
                                 "playlistmanager.js",
 
                                 "mediaplayer.js",
@@ -421,12 +422,14 @@ namespace MediaBrowser.WebDashboard.Api
                                 "itembynamedetailpage.js",
                                 "itemdetailpage.js",
                                 "itemlistpage.js",
+                                "kids.js",
                                 "librarypathmapping.js",
                                 "reports.js",
                                 "librarysettings.js",
                                 "livetvchannel.js",
                                 "livetvchannels.js",
                                 "livetvguide.js",
+                                "livetvitems.js",
                                 "livetvnewrecording.js",
                                 "livetvprogram.js",
                                 "livetvrecording.js",
@@ -470,7 +473,6 @@ namespace MediaBrowser.WebDashboard.Api
                                 "notificationlist.js",
                                 "notificationsetting.js",
                                 "notificationsettings.js",
-                                "playlist.js",
                                 "playlists.js",
                                 "playlistedit.js",
 
diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
index 812deabe11..f945ce0821 100644
--- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
+++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
@@ -87,6 +87,10 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <Content Include="dashboard-ui\css\images\clients\androidtv-tile.png" />
+    <Content Include="dashboard-ui\css\images\kids\bg.jpg">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\css\images\server.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -114,6 +118,12 @@
     <Content Include="dashboard-ui\forgotpasswordpin.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\kids.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="dashboard-ui\livetvitems.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\mysync.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -129,12 +139,21 @@
     <Content Include="dashboard-ui\scripts\forgotpasswordpin.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\scripts\kids.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="dashboard-ui\scripts\livetvitems.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\selectserver.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     <Content Include="dashboard-ui\scripts\syncjob.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\scripts\syncservices.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\syncsettings.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -156,6 +175,9 @@
     <Content Include="dashboard-ui\syncjob.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\syncservices.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\syncsettings.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -1752,9 +1774,6 @@
     <Content Include="dashboard-ui\songs.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\playlist.html">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\scripts\moviecollections.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -1800,9 +1819,6 @@
     <Content Include="dashboard-ui\scripts\songs.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
-    <Content Include="dashboard-ui\scripts\playlist.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\scripts\librarybrowser.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 66efd7c780..682175f793 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -193,6 +193,21 @@ namespace MediaBrowser.XbmcMetadata.Parsers
                         break;
                     }
 
+                case "originaltitle":
+                    {
+                        var val = reader.ReadElementContentAsString();
+
+                        var hasOriginalTitle = item as IHasOriginalTitle;
+                        if (hasOriginalTitle != null)
+                        {
+                            if (!string.IsNullOrEmpty(hasOriginalTitle.OriginalTitle))
+                            {
+                                hasOriginalTitle.OriginalTitle = val;
+                            }
+                        }
+                        break;
+                    }
+
                 case "title":
                 case "localtitle":
                     item.Name = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 5455709e99..3224f36bc6 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -214,7 +214,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
                 }
             }
 
-            using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+            using (var filestream = FileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
             {
                 stream.CopyTo(filestream);
             }
@@ -459,6 +459,15 @@ namespace MediaBrowser.XbmcMetadata.Savers
             writer.WriteElementString("title", item.Name ?? string.Empty);
             writer.WriteElementString("originaltitle", item.Name ?? string.Empty);
 
+            var hasOriginalTitle = item as IHasOriginalTitle;
+            if (hasOriginalTitle != null)
+            {
+                if (!string.IsNullOrEmpty(hasOriginalTitle.OriginalTitle))
+                {
+                    writer.WriteElementString("originaltitle", hasOriginalTitle.OriginalTitle ?? string.Empty);
+                }
+            } 
+            
             var directors = item.People
                 .Where(i => IsPersonType(i, PersonType.Director))
                 .Select(i => i.Name)
@@ -836,19 +845,26 @@ namespace MediaBrowser.XbmcMetadata.Savers
         private static void AddCollectionItems(Folder item, XmlWriter writer)
         {
             var items = item.LinkedChildren
-                .Where(i => i.Type == LinkedChildType.Manual && !string.IsNullOrWhiteSpace(i.ItemName))
+                .Where(i => i.Type == LinkedChildType.Manual)
                 .ToList();
 
             foreach (var link in items)
             {
                 writer.WriteStartElement("collectionitem");
 
-                writer.WriteElementString("name", link.ItemName);
-                writer.WriteElementString("type", link.ItemType);
+                if (!string.IsNullOrWhiteSpace(link.ItemName))
+                {
+                    writer.WriteElementString("name", link.ItemName);
+                }
+
+                if (!string.IsNullOrWhiteSpace(link.ItemType))
+                {
+                    writer.WriteElementString("type", link.ItemType);
+                }
 
-                if (link.ItemYear.HasValue)
+                if (!string.IsNullOrWhiteSpace(link.Path))
                 {
-                    writer.WriteElementString("year", link.ItemYear.Value.ToString(UsCulture));
+                    writer.WriteElementString("path", link.Path);
                 }
 
                 writer.WriteEndElement();
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index e657edb162..bbdce1f110 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.575</version>
+        <version>3.0.593</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.575" />
+            <dependency id="MediaBrowser.Common" version="3.0.593" />
             <dependency id="NLog" version="3.2.0.0" />
             <dependency id="SimpleInjector" version="2.7.0" />
         </dependencies>
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index eb940484c6..7aa7a9f695 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.575</version>
+        <version>3.0.593</version>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index 31301e1766..b33205c1e1 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
         <id>MediaBrowser.Model.Signed</id>
-        <version>3.0.575</version>
+        <version>3.0.593</version>
         <title>MediaBrowser.Model - Signed Edition</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 dca42fed73..9d6ad279ca 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.575</version>
+        <version>3.0.593</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.575" />
+            <dependency id="MediaBrowser.Common" version="3.0.593" />
         </dependencies>
     </metadata>
     <files>
diff --git a/SharedVersion.cs b/SharedVersion.cs
index d87daf5e3b..851d73ed7c 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,4 +1,4 @@
 using System.Reflection;
 
 //[assembly: AssemblyVersion("3.0.*")]
-[assembly: AssemblyVersion("3.0.5518.7")]
+[assembly: AssemblyVersion("3.0.5557.0")]