Browse Source

add connect to startup wizard

Luke Pulverenti 10 years ago
parent
commit
3be4aa8dc7
52 changed files with 2708 additions and 291 deletions
  1. 2 13
      MediaBrowser.Api/ApiEntryPoint.cs
  2. 0 7
      MediaBrowser.Api/MediaBrowser.Api.csproj
  3. 36 43
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 2 2
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  5. 44 0
      MediaBrowser.Api/Playback/StreamState.cs
  6. 9 0
      MediaBrowser.Api/UserService.cs
  7. 0 7
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  8. 6 0
      MediaBrowser.Controller/Entities/BaseItem.cs
  9. 6 0
      MediaBrowser.Controller/Entities/IHasImages.cs
  10. 10 0
      MediaBrowser.Controller/Entities/PhotoAlbum.cs
  11. 0 7
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  12. 10 0
      MediaBrowser.Controller/Playlists/Playlist.cs
  13. 13 0
      MediaBrowser.Controller/Providers/IProviderManager.cs
  14. 1 1
      MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs
  15. 1 1
      MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs
  16. 2 7
      MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs
  17. 30 4
      MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs
  18. 0 7
      MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
  19. 0 7
      MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj
  20. 3 1
      MediaBrowser.Model/ApiClient/ConnectionResult.cs
  21. 22 5
      MediaBrowser.Model/ApiClient/IConnectionManager.cs
  22. 97 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  23. 1 1
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  24. 0 7
      MediaBrowser.Model/MediaBrowser.Model.csproj
  25. 1 8
      MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs
  26. 22 10
      MediaBrowser.Providers/Manager/ImageSaver.cs
  27. 5 0
      MediaBrowser.Providers/Manager/ProviderManager.cs
  28. 1 7
      MediaBrowser.Providers/MediaBrowser.Providers.csproj
  29. 33 0
      MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs
  30. 1 3
      MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
  31. 6 1
      MediaBrowser.Server.Implementations/Library/UserManager.cs
  32. 1 1
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  33. 8 8
      MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
  34. 1 1
      MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
  35. 8 8
      MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
  36. 606 0
      MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json
  37. 1 0
      MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
  38. 6 6
      MediaBrowser.Server.Implementations/Localization/Server/it.json
  39. 6 6
      MediaBrowser.Server.Implementations/Localization/Server/kk.json
  40. 7 7
      MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
  41. 3 2
      MediaBrowser.Server.Implementations/Localization/Server/server.json
  42. 1229 0
      MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json
  43. 4 8
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  44. 113 68
      MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs
  45. 345 0
      MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs
  46. 0 7
      MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
  47. 0 7
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  48. 0 7
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
  49. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  50. 1 1
      Nuget/MediaBrowser.Common.nuspec
  51. 1 1
      Nuget/MediaBrowser.Model.Signed.nuspec
  52. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

+ 2 - 13
MediaBrowser.Api/ApiEntryPoint.cs

@@ -172,19 +172,8 @@ namespace MediaBrowser.Api
 
 
             if (!string.IsNullOrWhiteSpace(deviceId))
             if (!string.IsNullOrWhiteSpace(deviceId))
             {
             {
-                var audioCodec = state.Request.AudioCodec;
-                var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
-
-                if (string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase) ||
-                    string.IsNullOrEmpty(audioCodec))
-                {
-                    audioCodec = state.OutputAudioCodec;
-                }
-                if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) ||
-                    string.IsNullOrEmpty(videoCodec))
-                {
-                    videoCodec = state.OutputVideoCodec;
-                }
+                var audioCodec = state.ActualOutputVideoCodec;
+                var videoCodec = state.ActualOutputVideoCodec;
 
 
                 _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
                 _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo
                 {
                 {

+ 0 - 7
MediaBrowser.Api/MediaBrowser.Api.csproj

@@ -172,13 +172,6 @@
     <PostBuildEvent>
     <PostBuildEvent>
     </PostBuildEvent>
     </PostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
-  <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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 36 - 43
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -830,23 +830,6 @@ namespace MediaBrowser.Api.Playback
             return MediaEncoder.GetInputArgument(inputPath, protocol);
             return MediaEncoder.GetInputArgument(inputPath, protocol);
         }
         }
 
 
-        private MediaProtocol GetProtocol(string path)
-        {
-            if (path.StartsWith("Http", StringComparison.OrdinalIgnoreCase))
-            {
-                return MediaProtocol.Http;
-            }
-            if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase))
-            {
-                return MediaProtocol.Rtsp;
-            }
-            if (path.StartsWith("Rtmp", StringComparison.OrdinalIgnoreCase))
-            {
-                return MediaProtocol.Rtmp;
-            }
-            return MediaProtocol.File;
-        }
-
         private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
         private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
         {
         {
             if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
             if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
@@ -1788,9 +1771,23 @@ namespace MediaBrowser.Api.Playback
             }
             }
 
 
             // If client is requesting a specific video profile, it must match the source
             // If client is requesting a specific video profile, it must match the source
-            if (!string.IsNullOrEmpty(request.Profile) && !string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase))
+            if (!string.IsNullOrEmpty(request.Profile))
             {
             {
-                return false;
+                if (string.IsNullOrEmpty(videoStream.Profile))
+                {
+                    return false;
+                }
+
+                if (!string.Equals(request.Profile, videoStream.Profile, StringComparison.OrdinalIgnoreCase))
+                {
+                    var currentScore = GetVideoProfileScore(videoStream.Profile);
+                    var requestedScore = GetVideoProfileScore(request.Profile);
+
+                    if (currentScore == -1 || currentScore > requestedScore)
+                    {
+                        return false;
+                    }
+                }
             }
             }
 
 
             // Video width must fall within requested value
             // Video width must fall within requested value
@@ -1870,6 +1867,22 @@ namespace MediaBrowser.Api.Playback
             return request.EnableAutoStreamCopy;
             return request.EnableAutoStreamCopy;
         }
         }
 
 
+        private int GetVideoProfileScore(string profile)
+        {
+            var list = new List<string>
+            {
+                "Constrained Baseline",
+                "Baseline",
+                "Extended",
+                "Main",
+                "High",
+                "Progressive High",
+                "Constrained High"
+            };
+
+            return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
+        }
+
         private bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
         private bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List<string> supportedAudioCodecs)
         {
         {
             // Source and target codecs must match
             // Source and target codecs must match
@@ -1942,19 +1955,9 @@ namespace MediaBrowser.Api.Playback
                 return;
                 return;
             }
             }
 
 
-            var audioCodec = state.OutputAudioCodec;
-
-            if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
-            {
-                audioCodec = state.AudioStream.Codec;
-            }
-
-            var videoCodec = state.OutputVideoCodec;
+            var audioCodec = state.ActualOutputAudioCodec;
 
 
-            if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
-            {
-                videoCodec = state.VideoStream.Codec;
-            }
+            var videoCodec = state.ActualOutputVideoCodec;
 
 
             var mediaProfile = state.VideoRequest == null ?
             var mediaProfile = state.VideoRequest == null ?
                 profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate) :
                 profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate) :
@@ -2022,12 +2025,7 @@ namespace MediaBrowser.Api.Playback
                 profile = DlnaManager.GetDefaultProfile();
                 profile = DlnaManager.GetDefaultProfile();
             }
             }
 
 
-            var audioCodec = state.OutputAudioCodec;
-
-            if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
-            {
-                audioCodec = state.AudioStream.Codec;
-            }
+            var audioCodec = state.ActualOutputAudioCodec;
 
 
             if (state.VideoRequest == null)
             if (state.VideoRequest == null)
             {
             {
@@ -2045,12 +2043,7 @@ namespace MediaBrowser.Api.Playback
             }
             }
             else
             else
             {
             {
-                var videoCodec = state.OutputVideoCodec;
-
-                if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
-                {
-                    videoCodec = state.VideoStream.Codec;
-                }
+                var videoCodec = state.ActualOutputVideoCodec;
 
 
                 responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
                 responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
                     .BuildVideoHeader(
                     .BuildVideoHeader(

+ 2 - 2
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -605,7 +605,7 @@ namespace MediaBrowser.Api.Playback.Hls
         {
         {
             var codec = state.OutputAudioCodec;
             var codec = state.OutputAudioCodec;
 
 
-            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
+            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
             {
             {
                 return "-codec:a:0 copy";
                 return "-codec:a:0 copy";
             }
             }
@@ -636,7 +636,7 @@ namespace MediaBrowser.Api.Playback.Hls
             var codec = state.OutputVideoCodec;
             var codec = state.OutputVideoCodec;
 
 
             // See if we can save come cpu cycles by avoiding encoding
             // See if we can save come cpu cycles by avoiding encoding
-            if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase))
+            if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
             {
             {
                 return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
                 return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy";
             }
             }

+ 44 - 0
MediaBrowser.Api/Playback/StreamState.cs

@@ -188,6 +188,50 @@ namespace MediaBrowser.Api.Playback
         public int? OutputAudioBitrate;
         public int? OutputAudioBitrate;
         public int? OutputVideoBitrate;
         public int? OutputVideoBitrate;
 
 
+        public string ActualOutputVideoCodec
+        {
+            get
+            {
+                var codec = OutputVideoCodec;
+
+                if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+                {
+                    var stream = VideoStream;
+
+                    if (stream != null)
+                    {
+                        return stream.Codec;
+                    }
+
+                    return null;
+                }
+
+                return codec;
+            }
+        }
+
+        public string ActualOutputAudioCodec
+        {
+            get
+            {
+                var codec = OutputAudioCodec;
+
+                if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase))
+                {
+                    var stream = AudioStream;
+
+                    if (stream != null)
+                    {
+                        return stream.Codec;
+                    }
+
+                    return null;
+                }
+
+                return codec;
+            }
+        }
+
         public string OutputContainer { get; set; }
         public string OutputContainer { get; set; }
 
 
         public DeviceProfile DeviceProfile { get; set; }
         public DeviceProfile DeviceProfile { get; set; }

+ 9 - 0
MediaBrowser.Api/UserService.cs

@@ -29,6 +29,9 @@ namespace MediaBrowser.Api
 
 
         [ApiMember(Name = "IsDisabled", Description = "Optional filter by IsDisabled=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "IsDisabled", Description = "Optional filter by IsDisabled=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? IsDisabled { get; set; }
         public bool? IsDisabled { get; set; }
+
+        [ApiMember(Name = "IsGuest", Description = "Optional filter by IsGuest=true or false", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool? IsGuest { get; set; }
     }
     }
 
 
     [Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
     [Route("/Users/Public", "GET", Summary = "Gets a list of publicly visible users for display on a login screen.")]
@@ -255,6 +258,12 @@ namespace MediaBrowser.Api
                 users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value);
                 users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value);
             }
             }
 
 
+            if (request.IsGuest.HasValue)
+            {
+
+                users = users.Where(i => (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest) == request.IsGuest.Value);
+            }
+
             var result = users
             var result = users
                 .OrderBy(u => u.Name)
                 .OrderBy(u => u.Name)
                 .Select(i => _userManager.GetUserDto(i, Request.RemoteIp))
                 .Select(i => _userManager.GetUserDto(i, Request.RemoteIp))

+ 0 - 7
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -124,13 +124,6 @@
 xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
 xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
 )</PostBuildEvent>
 )</PostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
-  <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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 6 - 0
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -74,6 +74,12 @@ namespace MediaBrowser.Controller.Entities
             }
             }
         }
         }
 
 
+        [IgnoreDataMember]
+        public virtual bool AlwaysScanInternalMetadataPath
+        {
+            get { return false; }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets a value indicating whether this instance is in mixed folder.
         /// Gets a value indicating whether this instance is in mixed folder.
         /// </summary>
         /// </summary>

+ 6 - 0
MediaBrowser.Controller/Entities/IHasImages.cs

@@ -172,6 +172,12 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// </summary>
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         string GetInternalMetadataPath();
         string GetInternalMetadataPath();
+
+        /// <summary>
+        /// Gets a value indicating whether [always scan internal metadata path].
+        /// </summary>
+        /// <value><c>true</c> if [always scan internal metadata path]; otherwise, <c>false</c>.</value>
+        bool AlwaysScanInternalMetadataPath { get; }
     }
     }
 
 
     public static class HasImagesExtensions
     public static class HasImagesExtensions

+ 10 - 0
MediaBrowser.Controller/Entities/PhotoAlbum.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using System.Linq;
 using System.Linq;
+using System.Runtime.Serialization;
 
 
 namespace MediaBrowser.Controller.Entities
 namespace MediaBrowser.Controller.Entities
 {
 {
@@ -13,6 +14,15 @@ namespace MediaBrowser.Controller.Entities
             }
             }
         }
         }
 
 
+        [IgnoreDataMember]
+        public override bool AlwaysScanInternalMetadataPath
+        {
+            get
+            {
+                return true;
+            }
+        }
+        
         protected override bool GetBlockUnratedValue(UserConfiguration config)
         protected override bool GetBlockUnratedValue(UserConfiguration config)
         {
         {
             return config.BlockUnratedItems.Contains(UnratedItem.Other);
             return config.BlockUnratedItems.Contains(UnratedItem.Other);

+ 0 - 7
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -369,13 +369,6 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
     <PreBuildEvent>
     <PreBuildEvent>
     </PreBuildEvent>
     </PreBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
-  <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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 10 - 0
MediaBrowser.Controller/Playlists/Playlist.cs

@@ -15,6 +15,7 @@ namespace MediaBrowser.Controller.Playlists
     {
     {
         public string OwnerUserId { get; set; }
         public string OwnerUserId { get; set; }
 
 
+        [IgnoreDataMember]
         protected override bool FilterLinkedChildrenPerUser
         protected override bool FilterLinkedChildrenPerUser
         {
         {
             get
             get
@@ -23,6 +24,15 @@ namespace MediaBrowser.Controller.Playlists
             }
             }
         }
         }
 
 
+        [IgnoreDataMember]
+        public override bool AlwaysScanInternalMetadataPath
+        {
+            get
+            {
+                return true;
+            }
+        }
+
         public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
         public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren)
         {
         {
             return GetPlayableItems(user);
             return GetPlayableItems(user);

+ 13 - 0
MediaBrowser.Controller/Providers/IProviderManager.cs

@@ -49,6 +49,19 @@ namespace MediaBrowser.Controller.Providers
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken);
         Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken);
 
 
+        /// <summary>
+        /// Saves the image.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="source">The source.</param>
+        /// <param name="mimeType">Type of the MIME.</param>
+        /// <param name="type">The type.</param>
+        /// <param name="imageIndex">Index of the image.</param>
+        /// <param name="internalCacheKey">The internal cache key.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken);
+        
         /// <summary>
         /// <summary>
         /// Adds the metadata providers.
         /// Adds the metadata providers.
         /// </summary>
         /// </summary>

+ 1 - 1
MediaBrowser.LocalMetadata/Images/CollectionFolderImageProvider.cs

@@ -37,7 +37,7 @@ namespace MediaBrowser.LocalMetadata.Images
         {
         {
             var collectionFolder = (CollectionFolder)item;
             var collectionFolder = (CollectionFolder)item;
 
 
-            return new LocalImageProvider(_fileSystem).GetImages(item, collectionFolder.PhysicalLocations, directoryService);
+            return new LocalImageProvider(_fileSystem).GetImages(item, collectionFolder.PhysicalLocations, false, directoryService);
         }
         }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.LocalMetadata/Images/ImagesByNameImageProvider.cs

@@ -45,7 +45,7 @@ namespace MediaBrowser.LocalMetadata.Images
 
 
             try
             try
             {
             {
-                return new LocalImageProvider(_fileSystem).GetImages(item, path, directoryService);
+                return new LocalImageProvider(_fileSystem).GetImages(item, path, false, directoryService);
             }
             }
             catch (DirectoryNotFoundException)
             catch (DirectoryNotFoundException)
             {
             {

+ 2 - 7
MediaBrowser.LocalMetadata/Images/InternalMetadataFolderImageProvider.cs

@@ -38,7 +38,7 @@ namespace MediaBrowser.LocalMetadata.Images
                 return true;
                 return true;
             }
             }
 
 
-            if (item.SupportsLocalMetadata)
+            if (item.SupportsLocalMetadata && !item.AlwaysScanInternalMetadataPath)
             {
             {
                 return false;
                 return false;
             }
             }
@@ -59,14 +59,9 @@ namespace MediaBrowser.LocalMetadata.Images
         {
         {
             var path = item.GetInternalMetadataPath();
             var path = item.GetInternalMetadataPath();
 
 
-            if (item is IChannelItem)
-            {
-                var b = true;
-            }
-
             try
             try
             {
             {
-                return new LocalImageProvider(_fileSystem).GetImages(item, path, directoryService);
+                return new LocalImageProvider(_fileSystem).GetImages(item, path, true, directoryService);
             }
             }
             catch (DirectoryNotFoundException)
             catch (DirectoryNotFoundException)
             {
             {

+ 30 - 4
MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs

@@ -21,7 +21,7 @@ namespace MediaBrowser.LocalMetadata.Images
         {
         {
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
         }
         }
-        
+
         public string Name
         public string Name
         {
         {
             get { return "Local Images"; }
             get { return "Local Images"; }
@@ -94,12 +94,12 @@ namespace MediaBrowser.LocalMetadata.Images
             return list;
             return list;
         }
         }
 
 
-        public List<LocalImageInfo> GetImages(IHasImages item, string path, IDirectoryService directoryService)
+        public List<LocalImageInfo> GetImages(IHasImages item, string path, bool checkForCacheKeyFiles, IDirectoryService directoryService)
         {
         {
-            return GetImages(item, new[] { path }, directoryService);
+            return GetImages(item, new[] { path }, checkForCacheKeyFiles, directoryService);
         }
         }
 
 
-        public List<LocalImageInfo> GetImages(IHasImages item, IEnumerable<string> paths, IDirectoryService directoryService)
+        public List<LocalImageInfo> GetImages(IHasImages item, IEnumerable<string> paths, bool checkForCacheKeyFiles, IDirectoryService directoryService)
         {
         {
             var files = paths.SelectMany(directoryService.GetFiles)
             var files = paths.SelectMany(directoryService.GetFiles)
                 .Where(i =>
                 .Where(i =>
@@ -115,6 +115,12 @@ namespace MediaBrowser.LocalMetadata.Images
 
 
             PopulateImages(item, list, files, false, directoryService);
             PopulateImages(item, list, files, false, directoryService);
 
 
+            if (checkForCacheKeyFiles)
+            {
+                AddCacheKeyImage(files, list, ImageType.Primary);
+                AddCacheKeyImage(files, list, ImageType.Thumb);
+            }
+
             return list;
             return list;
         }
         }
 
 
@@ -322,6 +328,26 @@ namespace MediaBrowser.LocalMetadata.Images
             return false;
             return false;
         }
         }
 
 
+        private void AddCacheKeyImage(IEnumerable<FileSystemInfo> files, List<LocalImageInfo> images, ImageType type)
+        {
+            var candidates = files
+                .Where(i => _fileSystem.GetFileNameWithoutExtension(i).StartsWith(type.ToString() + "_key_", StringComparison.OrdinalIgnoreCase))
+                .ToList();
+
+            var image = BaseItem.SupportedImageExtensions
+                .Select(i => candidates.FirstOrDefault(c => string.Equals(c.Extension, i, StringComparison.OrdinalIgnoreCase)))
+                .FirstOrDefault(i => i != null) as FileInfo;
+
+            if (image != null)
+            {
+                images.Add(new LocalImageInfo
+                {
+                    FileInfo = image,
+                    Type = type
+                });
+            }
+        }
+
         private FileSystemInfo GetImage(IEnumerable<FileSystemInfo> files, string name)
         private FileSystemInfo GetImage(IEnumerable<FileSystemInfo> files, string name)
         {
         {
             var candidates = files
             var candidates = files

+ 0 - 7
MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj

@@ -91,13 +91,6 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup />
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 0 - 7
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -1118,13 +1118,6 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\portable\" /y /d /r /i
 )</PostBuildEvent>
 )</PostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="Fody.targets" />
   <Import Project="Fody.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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 3 - 1
MediaBrowser.Model/ApiClient/ConnectionResult.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using MediaBrowser.Model.Connect;
+using System.Collections.Generic;
 
 
 namespace MediaBrowser.Model.ApiClient
 namespace MediaBrowser.Model.ApiClient
 {
 {
@@ -7,6 +8,7 @@ namespace MediaBrowser.Model.ApiClient
         public ConnectionState State { get; set; }
         public ConnectionState State { get; set; }
         public List<ServerInfo> Servers { get; set; }
         public List<ServerInfo> Servers { get; set; }
         public IApiClient ApiClient { get; set; }
         public IApiClient ApiClient { get; set; }
+        public ConnectUser ConnectUser { get; set; }
 
 
         public ConnectionResult()
         public ConnectionResult()
         {
         {

+ 22 - 5
MediaBrowser.Model/ApiClient/IConnectionManager.cs

@@ -1,8 +1,8 @@
-using System.Collections.Generic;
-using MediaBrowser.Model.Connect;
+using MediaBrowser.Model.Connect;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Events;
 using System;
 using System;
+using System.Collections.Generic;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
@@ -14,12 +14,29 @@ namespace MediaBrowser.Model.ApiClient
         /// Occurs when [connected].
         /// Occurs when [connected].
         /// </summary>
         /// </summary>
         event EventHandler<GenericEventArgs<ConnectionResult>> Connected;
         event EventHandler<GenericEventArgs<ConnectionResult>> Connected;
+        /// <summary>
+        /// Occurs when [local user sign in].
+        /// </summary>
+        event EventHandler<GenericEventArgs<UserDto>> LocalUserSignIn;
+        /// <summary>
+        /// Occurs when [connect user sign in].
+        /// </summary>
+        event EventHandler<GenericEventArgs<ConnectUser>> ConnectUserSignIn;
+        /// <summary>
+        /// Occurs when [local user sign out].
+        /// </summary>
+        event EventHandler<EventArgs> LocalUserSignOut;
+        /// <summary>
+        /// Occurs when [connect user sign out].
+        /// </summary>
+        event EventHandler<EventArgs> ConnectUserSignOut;
 
 
         /// <summary>
         /// <summary>
-        /// Occurs when [remote logged out].
+        /// Gets the connect user.
         /// </summary>
         /// </summary>
-        event EventHandler<EventArgs> RemoteLoggedOut;
-        
+        /// <value>The connect user.</value>
+        ConnectUser ConnectUser { get; }
+
         /// <summary>
         /// <summary>
         /// Gets the API client.
         /// Gets the API client.
         /// </summary>
         /// </summary>

+ 97 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -238,6 +238,103 @@ namespace MediaBrowser.Model.Configuration
             {
             {
                 new MetadataOptions(1, 1280) {ItemType = "Book"},
                 new MetadataOptions(1, 1280) {ItemType = "Book"},
 
 
+                new MetadataOptions(1, 1280)
+                {
+                    ItemType = "Movie",
+                    ImageOptions = new []
+                    {
+                        new ImageOption
+                        {
+                            Limit = 3,
+                            MinWidth = 1280,
+                            Type = ImageType.Backdrop
+                        },
+
+                        // Don't download this by default as it's rarely used.
+                        new ImageOption
+                        {
+                            Limit = 0,
+                            Type = ImageType.Art
+                        },
+
+                        // Don't download this by default as it's rarely used.
+                        new ImageOption
+                        {
+                            Limit = 0,
+                            Type = ImageType.Disc
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Primary
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Banner
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Thumb
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Logo
+                        }
+                    }
+                },
+
+                new MetadataOptions(1, 1280)
+                {
+                    ItemType = "Series",
+                    ImageOptions = new []
+                    {
+                        new ImageOption
+                        {
+                            Limit = 2,
+                            MinWidth = 1280,
+                            Type = ImageType.Backdrop
+                        },
+
+                        // Don't download this by default as it's rarely used.
+                        new ImageOption
+                        {
+                            Limit = 0,
+                            Type = ImageType.Art
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Primary
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Banner
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Thumb
+                        },
+
+                        new ImageOption
+                        {
+                            Limit = 1,
+                            Type = ImageType.Logo
+                        }
+                    }
+                },
+
                 new MetadataOptions(1, 1280)
                 new MetadataOptions(1, 1280)
                 {
                 {
                     ItemType = "MusicAlbum",
                     ItemType = "MusicAlbum",

+ 1 - 1
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -674,7 +674,7 @@ namespace MediaBrowser.Model.Dlna
                         }
                         }
                     case ProfileConditionValue.VideoProfile:
                     case ProfileConditionValue.VideoProfile:
                         {
                         {
-                            item.VideoProfile = value;
+                            item.VideoProfile = (value ?? string.Empty).Split('|')[0];
                             break;
                             break;
                         }
                         }
                     case ProfileConditionValue.Height:
                     case ProfileConditionValue.Height:

+ 0 - 7
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -426,13 +426,6 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\net45\" /y /d /r /i
 )</PostBuildEvent>
 )</PostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="Fody.targets" />
   <Import Project="Fody.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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 1 - 8
MediaBrowser.Providers/FolderImages/DefaultImageProvider.cs

@@ -1,6 +1,5 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Providers;
@@ -33,12 +32,6 @@ namespace MediaBrowser.Providers.FolderImages
 
 
         public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
         public Task<IEnumerable<RemoteImageInfo>> GetImages(IHasImages item, CancellationToken cancellationToken)
         {
         {
-            var playlist = item as Playlist;
-            if (playlist != null)
-            {
-                return GetImages(string.Empty, cancellationToken);
-            }
-
             var view = item as UserView;
             var view = item as UserView;
 
 
             if (view != null)
             if (view != null)
@@ -119,7 +112,7 @@ namespace MediaBrowser.Providers.FolderImages
 
 
         public bool Supports(IHasImages item)
         public bool Supports(IHasImages item)
         {
         {
-            return item is UserView || item is ICollectionFolder || item is Playlist;
+            return item is UserView || item is ICollectionFolder;
         }
         }
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)

+ 22 - 10
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
@@ -63,7 +64,12 @@ namespace MediaBrowser.Providers.Manager
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         /// <exception cref="System.ArgumentNullException">mimeType</exception>
         /// <exception cref="System.ArgumentNullException">mimeType</exception>
-        public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+        public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken)
+        {
+            return SaveImage(item, source, mimeType, type, imageIndex, null, cancellationToken);
+        }
+
+        public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
         {
         {
             if (string.IsNullOrEmpty(mimeType))
             if (string.IsNullOrEmpty(mimeType))
             {
             {
@@ -108,6 +114,10 @@ namespace MediaBrowser.Providers.Manager
                     }
                     }
                 }
                 }
             }
             }
+            if (!string.IsNullOrEmpty(internalCacheKey))
+            {
+                saveLocally = false;
+            }
 
 
             if (!imageIndex.HasValue && item.AllowsMultipleImages(type))
             if (!imageIndex.HasValue && item.AllowsMultipleImages(type))
             {
             {
@@ -116,7 +126,9 @@ namespace MediaBrowser.Providers.Manager
 
 
             var index = imageIndex ?? 0;
             var index = imageIndex ?? 0;
 
 
-            var paths = GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
+            var paths = !string.IsNullOrEmpty(internalCacheKey) ?
+                new[] { GetCacheKeyPath(item, type, mimeType, internalCacheKey) } :
+                GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
 
 
             // If there are more than one output paths, the stream will need to be seekable
             // If there are more than one output paths, the stream will need to be seekable
             if (paths.Length > 1 && !source.CanSeek)
             if (paths.Length > 1 && !source.CanSeek)
@@ -180,6 +192,12 @@ namespace MediaBrowser.Providers.Manager
             }
             }
         }
         }
 
 
+        private string GetCacheKeyPath(IHasImages item, ImageType type, string mimeType, string key)
+        {
+            var extension = MimeTypes.ToExtension(mimeType);
+            return Path.Combine(item.GetInternalMetadataPath(), type.ToString().ToLower() + "_key_" + key + extension);
+        }
+
         /// <summary>
         /// <summary>
         /// Saves the image to location.
         /// Saves the image to location.
         /// </summary>
         /// </summary>
@@ -300,7 +318,7 @@ namespace MediaBrowser.Providers.Manager
         private string GetStandardSavePath(IHasImages item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
         private string GetStandardSavePath(IHasImages item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
         {
         {
             string filename;
             string filename;
-            
+
             switch (type)
             switch (type)
             {
             {
                 case ImageType.Art:
                 case ImageType.Art:
@@ -399,13 +417,7 @@ namespace MediaBrowser.Providers.Manager
         {
         {
             var season = item as Season;
             var season = item as Season;
 
 
-            var extension = mimeType.Split('/').Last();
-
-            if (string.Equals(extension, "jpeg", StringComparison.OrdinalIgnoreCase))
-            {
-                extension = "jpg";
-            }
-            extension = "." + extension.ToLower();
+            var extension = MimeTypes.ToExtension(mimeType);
 
 
             // Backdrop paths
             // Backdrop paths
             if (type == ImageType.Backdrop)
             if (type == ImageType.Backdrop)

+ 5 - 0
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -137,6 +137,11 @@ namespace MediaBrowser.Providers.Manager
             return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
             return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken);
         }
         }
 
 
+        public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, string internalCacheKey, CancellationToken cancellationToken)
+        {
+            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, internalCacheKey, cancellationToken);
+        }
+
         public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)
         public async Task<IEnumerable<RemoteImageInfo>> GetAvailableRemoteImages(IHasImages item, RemoteImageQuery query, CancellationToken cancellationToken)
         {
         {
             var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders);
             var providers = GetRemoteImageProviders(item, query.IncludeDisabledProviders);

+ 1 - 7
MediaBrowser.Providers/MediaBrowser.Providers.csproj

@@ -149,6 +149,7 @@
     <Compile Include="Music\MusicBrainzAlbumProvider.cs" />
     <Compile Include="Music\MusicBrainzAlbumProvider.cs" />
     <Compile Include="People\PersonMetadataService.cs" />
     <Compile Include="People\PersonMetadataService.cs" />
     <Compile Include="People\MovieDbPersonProvider.cs" />
     <Compile Include="People\MovieDbPersonProvider.cs" />
+    <Compile Include="Photos\PhotoAlbumMetadataService.cs" />
     <Compile Include="Photos\PhotoHelper.cs" />
     <Compile Include="Photos\PhotoHelper.cs" />
     <Compile Include="Photos\PhotoMetadataService.cs" />
     <Compile Include="Photos\PhotoMetadataService.cs" />
     <Compile Include="Photos\PhotoProvider.cs" />
     <Compile Include="Photos\PhotoProvider.cs" />
@@ -215,13 +216,6 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup />
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 33 - 0
MediaBrowser.Providers/Photos/PhotoAlbumMetadataService.cs

@@ -0,0 +1,33 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Providers.Manager;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Providers.Photos
+{
+    class PhotoAlbumMetadataService : MetadataService<PhotoAlbum, ItemLookupInfo>
+    {
+        public PhotoAlbumMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager)
+            : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager)
+        {
+        }
+
+        /// <summary>
+        /// Merges the specified source.
+        /// </summary>
+        /// <param name="source">The source.</param>
+        /// <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">if set to <c>true</c> [merge metadata settings].</param>
+        protected override void MergeData(PhotoAlbum source, PhotoAlbum target, List<MetadataFields> lockedFields, bool replaceData, bool mergeMetadataSettings)
+        {
+            ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings);
+        }
+    }
+}

+ 1 - 3
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs

@@ -1,6 +1,4 @@
-using System.Security.Cryptography;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;

+ 6 - 1
MediaBrowser.Server.Implementations/Library/UserManager.cs

@@ -159,7 +159,12 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("username");
                 throw new ArgumentNullException("username");
             }
             }
 
 
-            var user = Users.First(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
+            var user = Users.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
+
+            if (user == null)
+            {
+                throw new AuthenticationException("Invalid username or password entered.");
+            }
 
 
             if (user.Configuration.IsDisabled)
             if (user.Configuration.IsDisabled)
             {
             {

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -472,7 +472,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
 
             var item = _itemRepo.RetrieveItem(id) as LiveTvChannel;
             var item = _itemRepo.RetrieveItem(id) as LiveTvChannel;
 
 
-            if (item == null)
+            if (item == null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase))
             {
             {
                 item = new LiveTvChannel
                 item = new LiveTvChannel
                 {
                 {

+ 8 - 8
MediaBrowser.Server.Implementations/Localization/JavaScript/it.json

@@ -36,10 +36,10 @@
     "LabelMovie": "Film",
     "LabelMovie": "Film",
     "LabelMusicVideo": "Video Musicali",
     "LabelMusicVideo": "Video Musicali",
     "LabelEpisode": "Episodio",
     "LabelEpisode": "Episodio",
-    "LabelSeries": "Series",
+    "LabelSeries": "Serie TV",
     "LabelStopping": "Sto fermando",
     "LabelStopping": "Sto fermando",
     "LabelCancelled": "(cancellato)",
     "LabelCancelled": "(cancellato)",
-    "LabelFailed": "(failed)",
+    "LabelFailed": "(fallito)",
     "LabelAbortedByServerShutdown": "(Interrotto dalla chiusura del server)",
     "LabelAbortedByServerShutdown": "(Interrotto dalla chiusura del server)",
     "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
     "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.",
     "HeaderDeleteTaskTrigger": "Elimina Operazione pianificata",
     "HeaderDeleteTaskTrigger": "Elimina Operazione pianificata",
@@ -310,8 +310,8 @@
     "TabAdvanced": "Avanzato",
     "TabAdvanced": "Avanzato",
     "TabHelp": "Aiuto",
     "TabHelp": "Aiuto",
     "TabScheduledTasks": "Operazioni pianificate",
     "TabScheduledTasks": "Operazioni pianificate",
-    "ButtonFullscreen": "Fullscreen",
-    "ButtonAudioTracks": "Audio Tracks",
+    "ButtonFullscreen": "Schermo intero",
+    "ButtonAudioTracks": "Tracce audio",
     "ButtonSubtitles": "Sottotitoli",
     "ButtonSubtitles": "Sottotitoli",
     "ButtonScenes": "Scene",
     "ButtonScenes": "Scene",
     "ButtonQuality": "Qualit\u00e0",
     "ButtonQuality": "Qualit\u00e0",
@@ -383,7 +383,7 @@
     "PersonTypePerson": "Persona",
     "PersonTypePerson": "Persona",
     "LabelTitleDisplayOrder": "Titolo mostrato in ordine:",
     "LabelTitleDisplayOrder": "Titolo mostrato in ordine:",
     "OptionSortName": "Nome ordinato",
     "OptionSortName": "Nome ordinato",
-    "OptionReleaseDate": "Release date",
+    "OptionReleaseDate": "Data di uscita",
     "LabelSeasonNumber": "Numero Stagione:",
     "LabelSeasonNumber": "Numero Stagione:",
     "LabelDiscNumber": "Disco numero",
     "LabelDiscNumber": "Disco numero",
     "LabelParentNumber": "Numero superiore",
     "LabelParentNumber": "Numero superiore",
@@ -525,7 +525,7 @@
     "HeaderAlbums": "Album",
     "HeaderAlbums": "Album",
     "HeaderGames": "Giochi",
     "HeaderGames": "Giochi",
     "HeaderBooks": "Libri",
     "HeaderBooks": "Libri",
-    "HeaderEpisodes": "Episodes",
+    "HeaderEpisodes": "Episodi",
     "HeaderSeasons": "Stagioni",
     "HeaderSeasons": "Stagioni",
     "HeaderTracks": "Traccia",
     "HeaderTracks": "Traccia",
     "HeaderItems": "Elementi",
     "HeaderItems": "Elementi",
@@ -594,8 +594,8 @@
     "DashboardTourNotifications": "Inviare automaticamente notifiche di eventi server al vostro dispositivo mobile, e-mail e altro ancora.",
     "DashboardTourNotifications": "Inviare automaticamente notifiche di eventi server al vostro dispositivo mobile, e-mail e altro ancora.",
     "DashboardTourScheduledTasks": "Gestire facilmente le operazioni di lunga esecuzione con le operazioni pianificate. Decidere quando corrono, e con quale frequenza.",
     "DashboardTourScheduledTasks": "Gestire facilmente le operazioni di lunga esecuzione con le operazioni pianificate. Decidere quando corrono, e con quale frequenza.",
     "DashboardTourMobile": "Il cruscotto Media Browser funziona alla grande su smartphone e tablet. Gestisci il tuo server dal palmo della tua mano in qualsiasi momento, ovunque.",
     "DashboardTourMobile": "Il cruscotto Media Browser funziona alla grande su smartphone e tablet. Gestisci il tuo server dal palmo della tua mano in qualsiasi momento, ovunque.",
-    "MessageRefreshQueued": "Refresh queued",
-    "TabDevices": "Devices",
+    "MessageRefreshQueued": "Aggiornamento programmato",
+    "TabDevices": "Dispositivi",
     "DeviceLastUsedByUserName": "Last used by {0}",
     "DeviceLastUsedByUserName": "Last used by {0}",
     "HeaderDeleteDevice": "Delete Device",
     "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.",
     "DeleteDeviceConfirmation": "Are you sure you wish to delete this device? It will reappear the next time a user signs in with it.",

+ 1 - 1
MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json

@@ -601,6 +601,6 @@
     "DeleteDeviceConfirmation": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u0436\u0430\u0431\u0434\u044b\u049b\u0442\u044b \u0436\u043e\u044e \u049b\u0430\u0436\u0435\u0442 \u043f\u0435? \u0411\u04b1\u043b \u043a\u0435\u043b\u0435\u0441\u0456 \u0440\u0435\u0442\u0442\u0435 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u043e\u0441\u044b\u0434\u0430\u043d \u043a\u0456\u0440\u0433\u0435\u043d\u0434\u0435 \u049b\u0430\u0439\u0442\u0430 \u043f\u0430\u0439\u0434\u0430 \u0431\u043e\u043b\u0430\u0434\u044b.",
     "DeleteDeviceConfirmation": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u0436\u0430\u0431\u0434\u044b\u049b\u0442\u044b \u0436\u043e\u044e \u049b\u0430\u0436\u0435\u0442 \u043f\u0435? \u0411\u04b1\u043b \u043a\u0435\u043b\u0435\u0441\u0456 \u0440\u0435\u0442\u0442\u0435 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u043e\u0441\u044b\u0434\u0430\u043d \u043a\u0456\u0440\u0433\u0435\u043d\u0434\u0435 \u049b\u0430\u0439\u0442\u0430 \u043f\u0430\u0439\u0434\u0430 \u0431\u043e\u043b\u0430\u0434\u044b.",
     "LabelEnableCameraUploadFor": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u043a\u0430\u043c\u0435\u0440\u0430\u0434\u0430\u043d \u043a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443:",
     "LabelEnableCameraUploadFor": "\u041c\u044b\u043d\u0430\u0443 \u04af\u0448\u0456\u043d \u043a\u0430\u043c\u0435\u0440\u0430\u0434\u0430\u043d \u043a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443:",
     "HeaderSelectUploadPath": "\u041a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
     "HeaderSelectUploadPath": "\u041a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
-    "LabelEnableCameraUploadForHelp": "Uploads will occur automatically in the background when signed into Media Browser.",
+    "LabelEnableCameraUploadForHelp": "Media Browser \u0456\u0448\u0456\u043d\u0435 \u043a\u0456\u0440\u0433\u0435\u043d\u0434\u0435 \u043a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443\u043b\u0430\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u04e9\u043d\u0434\u0456\u043a \u0440\u0435\u0436\u0456\u043c\u0456\u043d\u0434\u0435 \u04e9\u0442\u0435\u0434\u0456.",
     "ErrorMessageStartHourGreaterThanEnd": "\u0410\u044f\u049b\u0442\u0430\u0443 \u0443\u0430\u049b\u044b\u0442\u044b \u0431\u0430\u0441\u0442\u0430\u0443 \u0443\u0430\u049b\u044b\u0442\u044b\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d\u0440\u0435\u043a \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0434\u0456."
     "ErrorMessageStartHourGreaterThanEnd": "\u0410\u044f\u049b\u0442\u0430\u0443 \u0443\u0430\u049b\u044b\u0442\u044b \u0431\u0430\u0441\u0442\u0430\u0443 \u0443\u0430\u049b\u044b\u0442\u044b\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d\u0440\u0435\u043a \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0434\u0456."
 }
 }

+ 8 - 8
MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json

@@ -36,10 +36,10 @@
     "LabelMovie": "Filme",
     "LabelMovie": "Filme",
     "LabelMusicVideo": "V\u00eddeo Musical",
     "LabelMusicVideo": "V\u00eddeo Musical",
     "LabelEpisode": "Epis\u00f3dio",
     "LabelEpisode": "Epis\u00f3dio",
-    "LabelSeries": "Series",
+    "LabelSeries": "S\u00e9rie",
     "LabelStopping": "Parando",
     "LabelStopping": "Parando",
     "LabelCancelled": "(cancelado)",
     "LabelCancelled": "(cancelado)",
-    "LabelFailed": "(failed)",
+    "LabelFailed": "(falhou)",
     "LabelAbortedByServerShutdown": "(Abortada pelo desligamento do servidor)",
     "LabelAbortedByServerShutdown": "(Abortada pelo desligamento do servidor)",
     "LabelScheduledTaskLastRan": "\u00daltima execu\u00e7\u00e3o {0}, demorando {1}.",
     "LabelScheduledTaskLastRan": "\u00daltima execu\u00e7\u00e3o {0}, demorando {1}.",
     "HeaderDeleteTaskTrigger": "Excluir Disparador da Tarefa",
     "HeaderDeleteTaskTrigger": "Excluir Disparador da Tarefa",
@@ -63,7 +63,7 @@
     "ButtonPlay": "Reproduzir",
     "ButtonPlay": "Reproduzir",
     "ButtonEdit": "Editar",
     "ButtonEdit": "Editar",
     "ButtonQueue": "Adicionar \u00e0 fila",
     "ButtonQueue": "Adicionar \u00e0 fila",
-    "ButtonPlayTrailer": "Play trailer",
+    "ButtonPlayTrailer": "Reproduzir trailer",
     "ButtonPlaylist": "Lista de reprodu\u00e7\u00e3o",
     "ButtonPlaylist": "Lista de reprodu\u00e7\u00e3o",
     "ButtonPreviousTrack": "Faixa Anterior",
     "ButtonPreviousTrack": "Faixa Anterior",
     "LabelEnabled": "Ativada",
     "LabelEnabled": "Ativada",
@@ -310,8 +310,8 @@
     "TabAdvanced": "Avan\u00e7ado",
     "TabAdvanced": "Avan\u00e7ado",
     "TabHelp": "Ajuda",
     "TabHelp": "Ajuda",
     "TabScheduledTasks": "Tarefas Agendadas",
     "TabScheduledTasks": "Tarefas Agendadas",
-    "ButtonFullscreen": "Fullscreen",
-    "ButtonAudioTracks": "Audio Tracks",
+    "ButtonFullscreen": "Tela cheia",
+    "ButtonAudioTracks": "Faixas de \u00c1udio",
     "ButtonSubtitles": "Legendas",
     "ButtonSubtitles": "Legendas",
     "ButtonScenes": "Cenas",
     "ButtonScenes": "Cenas",
     "ButtonQuality": "Qualidade",
     "ButtonQuality": "Qualidade",
@@ -383,7 +383,7 @@
     "PersonTypePerson": "Pessoa",
     "PersonTypePerson": "Pessoa",
     "LabelTitleDisplayOrder": "Ordem de exibi\u00e7\u00e3o do t\u00edtulo: ",
     "LabelTitleDisplayOrder": "Ordem de exibi\u00e7\u00e3o do t\u00edtulo: ",
     "OptionSortName": "Nome para ordena\u00e7\u00e3o",
     "OptionSortName": "Nome para ordena\u00e7\u00e3o",
-    "OptionReleaseDate": "Release date",
+    "OptionReleaseDate": "Data de lan\u00e7amento",
     "LabelSeasonNumber": "N\u00famero da temporada:",
     "LabelSeasonNumber": "N\u00famero da temporada:",
     "LabelDiscNumber": "N\u00famero do disco",
     "LabelDiscNumber": "N\u00famero do disco",
     "LabelParentNumber": "N\u00famero do superior",
     "LabelParentNumber": "N\u00famero do superior",
@@ -525,7 +525,7 @@
     "HeaderAlbums": "\u00c1lbuns",
     "HeaderAlbums": "\u00c1lbuns",
     "HeaderGames": "Jogos",
     "HeaderGames": "Jogos",
     "HeaderBooks": "Livros",
     "HeaderBooks": "Livros",
-    "HeaderEpisodes": "Episodes",
+    "HeaderEpisodes": "Epis\u00f3dios",
     "HeaderSeasons": "Temporadas",
     "HeaderSeasons": "Temporadas",
     "HeaderTracks": "Faixas",
     "HeaderTracks": "Faixas",
     "HeaderItems": "Itens",
     "HeaderItems": "Itens",
@@ -602,5 +602,5 @@
     "LabelEnableCameraUploadFor": "Habilitar envio atrav\u00e9s de c\u00e2mera para:",
     "LabelEnableCameraUploadFor": "Habilitar envio atrav\u00e9s de c\u00e2mera para:",
     "HeaderSelectUploadPath": "Selecione o caminho para carga",
     "HeaderSelectUploadPath": "Selecione o caminho para carga",
     "LabelEnableCameraUploadForHelp": "Cargas ser\u00e3o executadas automaticamente em retaguarda quando logar no Media Browser.",
     "LabelEnableCameraUploadForHelp": "Cargas ser\u00e3o executadas automaticamente em retaguarda quando logar no Media Browser.",
-    "ErrorMessageStartHourGreaterThanEnd": "End time must be greater than the start time."
+    "ErrorMessageStartHourGreaterThanEnd": "O tempo final deve ser maior que o tempo inicial."
 }
 }

+ 606 - 0
MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json

@@ -0,0 +1,606 @@
+{
+    "SettingsSaved": "\u8bbe\u7f6e\u5df2\u4fdd\u5b58",
+    "AddUser": "\u6dfb\u52a0\u7528\u6237",
+    "Users": "\u7528\u6237",
+    "Delete": "\u5220\u9664",
+    "Administrator": "\u7ba1\u7406\u5458",
+    "Password": "\u5bc6\u7801",
+    "DeleteImage": "\u5220\u9664\u56fe\u50cf",
+    "DeleteImageConfirmation": "\u4f60\u786e\u5b9a\u8981\u5220\u9664\u6b64\u56fe\u50cf\uff1f",
+    "FileReadCancelled": "\u6587\u4ef6\u8bfb\u53d6\u5df2\u88ab\u53d6\u6d88\u3002",
+    "FileNotFound": "\u672a\u627e\u5230\u6587\u4ef6\u3002",
+    "FileReadError": "\u8bfb\u53d6\u6587\u4ef6\u53d1\u751f\u9519\u8bef\u3002",
+    "DeleteUser": "\u5220\u9664\u7528\u6237",
+    "DeleteUserConfirmation": "\u4f60\u786e\u5b9a\u8981\u5220\u9664\u6b64\u7528\u6237\uff1f",
+    "PasswordResetHeader": "\u5bc6\u7801\u91cd\u7f6e",
+    "PasswordResetComplete": "\u5bc6\u7801\u5df2\u91cd\u7f6e",
+    "PasswordResetConfirmation": "\u4f60\u786e\u5b9a\u8981\u91cd\u7f6e\u5bc6\u7801\uff1f",
+    "PasswordSaved": "\u5bc6\u7801\u5df2\u4fdd\u5b58\u3002",
+    "PasswordMatchError": "\u5bc6\u7801\u548c\u786e\u8ba4\u5bc6\u7801\u5fc5\u987b\u5339\u914d\u3002",
+    "OptionRelease": "\u5b98\u65b9\u6b63\u5f0f\u7248",
+    "OptionBeta": "\u6d4b\u8bd5\u7248",
+    "OptionDev": "\u5f00\u53d1\u7248\uff08\u4e0d\u7a33\u5b9a\uff09",
+    "UninstallPluginHeader": "\u5378\u8f7d\u63d2\u4ef6",
+    "UninstallPluginConfirmation": "\u4f60\u786e\u5b9a\u8981\u5378\u8f7d {0}?",
+    "NoPluginConfigurationMessage": "\u6b64\u63d2\u4ef6\u6ca1\u6709\u914d\u7f6e\u9009\u9879\u3002",
+    "NoPluginsInstalledMessage": "\u4f60\u6ca1\u6709\u5b89\u88c5\u63d2\u4ef6\u3002",
+    "BrowsePluginCatalogMessage": "\u6d4f\u89c8\u6211\u4eec\u7684\u63d2\u4ef6\u76ee\u5f55\u6765\u67e5\u770b\u73b0\u6709\u63d2\u4ef6\u3002",
+    "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.",
+    "HeaderSearch": "Search",
+    "LabelArtist": "Artist",
+    "LabelMovie": "Movie",
+    "LabelMusicVideo": "Music Video",
+    "LabelEpisode": "Episode",
+    "LabelSeries": "Series",
+    "LabelStopping": "Stopping",
+    "LabelCancelled": "(cancelled)",
+    "LabelFailed": "(failed)",
+    "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",
+    "HeaderSelectAudio": "Select Audio",
+    "HeaderSelectSubtitles": "Select Subtitles",
+    "LabelDefaultStream": "(Default)",
+    "LabelForcedStream": "(Forced)",
+    "LabelDefaultForcedStream": "(Default\/Forced)",
+    "LabelUnknownLanguage": "Unknown language",
+    "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 user or password.",
+    "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",
+    "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}",
+    "LabelRemoteAccessUrl": "Remote access: {0}",
+    "LabelRunningOnPort": "Running on port {0}.",
+    "HeaderLatestFromChannel": "Latest from {0}",
+    "ButtonDownload": "Download",
+    "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",
+    "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",
+    "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 items 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": "Are you sure you wish to delete this item from your library?",
+    "MessagePleaseEnterNameOrId": "Please enter a name or an external Id.",
+    "MessageValueNotCorrect": "The value entered is not correct. Please try again.",
+    "MessageItemSaved": "Item saved.",
+    "OptionEnded": "Ended",
+    "OptionContinuing": "Continuing",
+    "OptionOff": "Off",
+    "OptionOn": "On",
+    "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 Folder Type",
+    "HeaderChangeFolderTypeHelp": "To change the folder type, please remove and rebuild the collection 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": "Fullscreen",
+    "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:",
+    "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",
+    "LabelFolderTypeValue": "Folder type: {0}",
+    "LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.",
+    "FolderTypeMixed": "Mixed movies & tv",
+    "FolderTypeMovies": "Movies",
+    "FolderTypeMusic": "Music",
+    "FolderTypeAdultVideos": "Adult videos",
+    "FolderTypePhotos": "Photos",
+    "FolderTypeMusicVideos": "Music videos",
+    "FolderTypeHomeVideos": "Home videos",
+    "FolderTypeGames": "Games",
+    "FolderTypeBooks": "Books",
+    "FolderTypeTvShows": "TV shows",
+    "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}",
+    "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",
+    "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",
+    "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.",
+    "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.",
+    "MessageRefreshQueued": "Refresh queued",
+    "TabDevices": "Devices",
+    "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."
+}

+ 1 - 0
MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs

@@ -362,6 +362,7 @@ namespace MediaBrowser.Server.Implementations.Localization
                 new LocalizatonOption{ Name="English (United Kingdom)", Value="en-GB"},
                 new LocalizatonOption{ Name="English (United Kingdom)", Value="en-GB"},
                 new LocalizatonOption{ Name="English (United States)", Value="en-us"},
                 new LocalizatonOption{ Name="English (United States)", Value="en-us"},
                 new LocalizatonOption{ Name="Catalan", Value="ca"},
                 new LocalizatonOption{ Name="Catalan", Value="ca"},
+                new LocalizatonOption{ Name="Chinese Simplified", Value="zh-CN"},
                 new LocalizatonOption{ Name="Chinese Traditional", Value="zh-TW"},
                 new LocalizatonOption{ Name="Chinese Traditional", Value="zh-TW"},
                 new LocalizatonOption{ Name="Croatian", Value="hr"},
                 new LocalizatonOption{ Name="Croatian", Value="hr"},
                 new LocalizatonOption{ Name="Czech", Value="cs"},
                 new LocalizatonOption{ Name="Czech", Value="cs"},

+ 6 - 6
MediaBrowser.Server.Implementations/Localization/Server/it.json

@@ -152,7 +152,7 @@
     "LabelWebsite": "Sito web:",
     "LabelWebsite": "Sito web:",
     "ButtonAddLocalUser": "Aggiungi Utente locale",
     "ButtonAddLocalUser": "Aggiungi Utente locale",
     "LabelTagline": "Messaggio pers:",
     "LabelTagline": "Messaggio pers:",
-    "ButtonInviteUser": "Invite User",
+    "ButtonInviteUser": "Invita un utente",
     "ButtonSave": "Salva",
     "ButtonSave": "Salva",
     "LabelOverview": "Trama:",
     "LabelOverview": "Trama:",
     "ButtonResetPassword": "Reset Password",
     "ButtonResetPassword": "Reset Password",
@@ -404,11 +404,11 @@
     "OptionFriday": "Venerdi",
     "OptionFriday": "Venerdi",
     "LabelNumberTrailerToPlay": "Number of trailers to play:",
     "LabelNumberTrailerToPlay": "Number of trailers to play:",
     "OptionSaturday": "Sabato",
     "OptionSaturday": "Sabato",
-    "TitleDevices": "Devices",
+    "TitleDevices": "Dispositivi",
     "HeaderManagement": "Gestione :",
     "HeaderManagement": "Gestione :",
     "TabCameraUpload": "Camera Upload",
     "TabCameraUpload": "Camera Upload",
     "LabelManagement": "Management:",
     "LabelManagement": "Management:",
-    "TabDevices": "Devices",
+    "TabDevices": "Dispositivi",
     "OptionMissingImdbId": "IMDB id mancante",
     "OptionMissingImdbId": "IMDB id mancante",
     "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Media Browser.",
     "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Media Browser.",
     "OptionMissingTvdbId": "TheTVDB Id mancante",
     "OptionMissingTvdbId": "TheTVDB Id mancante",
@@ -436,7 +436,7 @@
     "SearchKnowledgeBase": "Cerca sulla guida online",
     "SearchKnowledgeBase": "Cerca sulla guida online",
     "HeaderGuests": "Guests",
     "HeaderGuests": "Guests",
     "VisitTheCommunity": "Visita la nostra comunit\u00e0",
     "VisitTheCommunity": "Visita la nostra comunit\u00e0",
-    "HeaderLocalUsers": "Local Users",
+    "HeaderLocalUsers": "Utenti locale",
     "VisitMediaBrowserWebsite": "Visita il sito di Media Browser",
     "VisitMediaBrowserWebsite": "Visita il sito di Media Browser",
     "HeaderPendingInvitations": "Pending Invitations",
     "HeaderPendingInvitations": "Pending Invitations",
     "VisitMediaBrowserWebsiteLong": "Vuoi saperne di pi\u00f9 sulle ultime novit\u00e0?",
     "VisitMediaBrowserWebsiteLong": "Vuoi saperne di pi\u00f9 sulle ultime novit\u00e0?",
@@ -689,12 +689,12 @@
     "NewCollectionNameExample": "Esempio:Collezione Star wars",
     "NewCollectionNameExample": "Esempio:Collezione Star wars",
     "OptionSearchForInternetMetadata": "Cerca su internet le immagini e i metadati",
     "OptionSearchForInternetMetadata": "Cerca su internet le immagini e i metadati",
     "ButtonCreate": "Crea",
     "ButtonCreate": "Crea",
-    "LabelLocalHttpServerPortNumber": "Local port number:",
+    "LabelLocalHttpServerPortNumber": "Numero di porta locale:",
     "LabelLocalHttpServerPortNumberHelp": "The tcp port number that Media Browser's http server should bind to.",
     "LabelLocalHttpServerPortNumberHelp": "The tcp port number that Media Browser's http server should bind to.",
     "LabelPublicPort": "Public port number:",
     "LabelPublicPort": "Public port number:",
     "LabelPublicPortHelp": "The public port number that should be mapped to the local port.",
     "LabelPublicPortHelp": "The public port number that should be mapped to the local port.",
     "LabelWebSocketPortNumber": "Porta webSocket numero:",
     "LabelWebSocketPortNumber": "Porta webSocket numero:",
-    "LabelEnableAutomaticPortMap": "Enable automatic port mapping",
+    "LabelEnableAutomaticPortMap": "Abilita mappatura delle porte automatiche",
     "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models.",
     "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models.",
     "LabelExternalDDNS": "DDNS Esterno:",
     "LabelExternalDDNS": "DDNS Esterno:",
     "LabelExternalDDNSHelp": "Se tu ha un DNS dinamico inseriscilo qui.Media browser lo utilizzera per le connessioni remote.",
     "LabelExternalDDNSHelp": "Se tu ha un DNS dinamico inseriscilo qui.Media browser lo utilizzera per le connessioni remote.",

+ 6 - 6
MediaBrowser.Server.Implementations/Localization/Server/kk.json

@@ -410,27 +410,27 @@
     "LabelManagement": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440",
     "LabelManagement": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440",
     "TabDevices": "\u0416\u0430\u0431\u0434\u044b\u049b\u0442\u0430\u0440",
     "TabDevices": "\u0416\u0430\u0431\u0434\u044b\u049b\u0442\u0430\u0440",
     "OptionMissingImdbId": "IMDb Id \u0436\u043e\u049b",
     "OptionMissingImdbId": "IMDb Id \u0436\u043e\u049b",
-    "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Media Browser.",
+    "HeaderCameraUploadHelp": "\u04b0\u0442\u049b\u044b\u0440 \u0436\u0430\u0431\u0434\u044b\u049b\u0442\u0430\u0440\u044b\u04a3\u044b\u0437\u0431\u0435\u043d \u0442\u04af\u0441\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0444\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440 \u043c\u0435\u043d \u0431\u0435\u0439\u043d\u0435\u0444\u0430\u0439\u043b\u0434\u0430\u0440\u0434\u044b Media Browser \u0456\u0448\u0456\u043d\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u049b\u043e\u0442\u0430\u0440\u044b\u043f \u0431\u0435\u0440\u0443.",
     "OptionMissingTvdbId": "TheTVDB Id \u0436\u043e\u049b",
     "OptionMissingTvdbId": "TheTVDB Id \u0436\u043e\u049b",
-    "MessageNoDevicesSupportCameraUpload": "You currently don't have any devices that support camera upload.",
+    "MessageNoDevicesSupportCameraUpload": "\u0410\u0493\u044b\u043c\u0434\u0430 \u043a\u0430\u043c\u0435\u0440\u0430\u0434\u0430\u043d \u049b\u043e\u0442\u0430\u0440\u044b\u043f \u0431\u0435\u0440\u0435\u0442\u0456\u043d \u0435\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u0436\u0430\u0431\u0434\u044b\u049b\u0442\u0430\u0440\u044b\u04a3\u044b\u0437 \u0436\u043e\u049b.",
     "OptionMissingOverview": "\u0416\u0430\u043b\u043f\u044b \u0448\u043e\u043b\u0443 \u0436\u043e\u049b",
     "OptionMissingOverview": "\u0416\u0430\u043b\u043f\u044b \u0448\u043e\u043b\u0443 \u0436\u043e\u049b",
     "LabelCameraUploadPath": "\u041a\u0430\u043c\u0435\u0440\u0430\u0434\u0430\u043d \u043a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443 \u0436\u043e\u043b\u044b:",
     "LabelCameraUploadPath": "\u041a\u0430\u043c\u0435\u0440\u0430\u0434\u0430\u043d \u043a\u0435\u0440\u0456 \u049b\u043e\u0442\u0430\u0440\u0443 \u0436\u043e\u043b\u044b:",
     "OptionFileMetadataYearMismatch": "\u0424\u0430\u0439\u043b\/\u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a \u0436\u044b\u043b\u044b \u0441\u04d9\u0439\u043a\u0435\u0441 \u0435\u043c\u0435\u0441",
     "OptionFileMetadataYearMismatch": "\u0424\u0430\u0439\u043b\/\u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a \u0436\u044b\u043b\u044b \u0441\u04d9\u0439\u043a\u0435\u0441 \u0435\u043c\u0435\u0441",
-    "LabelCameraUploadPathHelp": "Select a custom upload path, if desired. If unspecified a default folder will be used.",
+    "LabelCameraUploadPathHelp": "\u0415\u0433\u0435\u0440 \u043a\u0435\u0440\u0435\u043a \u0431\u043e\u043b\u0441\u0430, \u049b\u043e\u0442\u0430\u0440\u044b\u043f \u0431\u0435\u0440\u0443 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u043e\u043b\u0434\u044b \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437. \u0415\u0433\u0435\u0440 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u043c\u0435\u0441\u0435, \u04d9\u0434\u0435\u043f\u043a\u0456 \u049b\u0430\u043b\u0442\u0430 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043b\u0430\u0434\u044b.",
     "TabGeneral": "\u0416\u0430\u043b\u043f\u044b",
     "TabGeneral": "\u0416\u0430\u043b\u043f\u044b",
     "LabelCreateCameraUploadSubfolder": "\u04d8\u0440\u049b\u0430\u0439\u0441\u044b \u0436\u0430\u0431\u0434\u044b\u049b \u04af\u0448\u0456\u043d \u0456\u0448\u043a\u0456 \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0441\u0430\u0443",
     "LabelCreateCameraUploadSubfolder": "\u04d8\u0440\u049b\u0430\u0439\u0441\u044b \u0436\u0430\u0431\u0434\u044b\u049b \u04af\u0448\u0456\u043d \u0456\u0448\u043a\u0456 \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0441\u0430\u0443",
     "TitleSupport": "\u049a\u043e\u043b\u0434\u0430\u0443",
     "TitleSupport": "\u049a\u043e\u043b\u0434\u0430\u0443",
-    "LabelCreateCameraUploadSubfolderHelp": "Specific folders can be assigned to a device by clicking on it from the Devices page.",
+    "LabelCreateCameraUploadSubfolderHelp": "\u0416\u0430\u0431\u0434\u044b\u049b\u0442\u0430\u0440 \u0431\u0435\u0442\u0456\u043d\u0434\u0435 \u043d\u04b1\u049b\u044b\u0493\u0430\u043d\u0434\u0430 \u0436\u0430\u0431\u0434\u044b\u049b\u049b\u0430 \u043d\u0430\u049b\u0442\u044b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440 \u0442\u0430\u0493\u0430\u0439\u044b\u043d\u0434\u0430\u043b\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.",
     "TabLog": "\u0416\u04b1\u0440\u043d\u0430\u043b",
     "TabLog": "\u0416\u04b1\u0440\u043d\u0430\u043b",
     "LabelCustomDeviceDisplayName": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0443 \u0430\u0442\u044b:",
     "LabelCustomDeviceDisplayName": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0443 \u0430\u0442\u044b:",
     "TabAbout": "\u0422\u0443\u0440\u0430\u043b\u044b",
     "TabAbout": "\u0422\u0443\u0440\u0430\u043b\u044b",
-    "LabelCustomDeviceDisplayNameHelp": "Supply a custom display name or leave empty to use the name reported by the device.",
+    "LabelCustomDeviceDisplayNameHelp": "\u0411\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0435\u0442\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0430\u0442\u044b\u043d \u04b1\u0441\u044b\u043d\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0436\u0430\u0431\u0434\u044b\u049b \u0430\u0440\u049b\u044b\u043b\u044b \u0431\u0430\u044f\u043d\u0434\u0430\u043b\u0493\u0430\u043d \u0430\u0442\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0431\u043e\u0441 \u049b\u0430\u043b\u0434\u044b\u0440\u044b\u04a3\u044b\u0437.",
     "TabSupporterKey": "\u049a\u043e\u043b\u0434\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456",
     "TabSupporterKey": "\u049a\u043e\u043b\u0434\u0430\u0443\u0448\u044b \u043a\u0456\u043b\u0442\u0456",
     "HeaderInviteUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u0448\u0430\u049b\u044b\u0440\u0443",
     "HeaderInviteUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b \u0448\u0430\u049b\u044b\u0440\u0443",
     "TabBecomeSupporter": "\u049a\u043e\u043b\u0434\u0430\u0443\u0448\u044b \u0431\u043e\u043b\u0443",
     "TabBecomeSupporter": "\u049a\u043e\u043b\u0434\u0430\u0443\u0448\u044b \u0431\u043e\u043b\u0443",
     "LabelConnectInviteUserHelp": "\u0411\u04b1\u043b \u0434\u043e\u0441\u0442\u0430\u0440\u044b\u04a3\u044b\u0437\u0434\u044b\u04a3 Media Browser \u0493\u0430\u043b\u0430\u043c\u0442\u043e\u0440 \u0441\u0430\u0439\u0442\u044b\u043d\u0430 \u043a\u0456\u0440\u0433\u0435\u043d\u0434\u0435 \u049b\u043e\u043b\u0434\u0430\u043d\u0430\u0442\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u044b \u043d\u0435\u043c\u0435\u0441\u0435 \u0435-\u043f\u043e\u0448\u0442\u0430 \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b \u0431\u043e\u043b\u044b\u043f \u0442\u0430\u0431\u044b\u043b\u0430\u0434\u044b.",
     "LabelConnectInviteUserHelp": "\u0411\u04b1\u043b \u0434\u043e\u0441\u0442\u0430\u0440\u044b\u04a3\u044b\u0437\u0434\u044b\u04a3 Media Browser \u0493\u0430\u043b\u0430\u043c\u0442\u043e\u0440 \u0441\u0430\u0439\u0442\u044b\u043d\u0430 \u043a\u0456\u0440\u0433\u0435\u043d\u0434\u0435 \u049b\u043e\u043b\u0434\u0430\u043d\u0430\u0442\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b \u0430\u0442\u044b \u043d\u0435\u043c\u0435\u0441\u0435 \u0435-\u043f\u043e\u0448\u0442\u0430 \u043c\u0435\u043a\u0435\u043d\u0436\u0430\u0439\u044b \u0431\u043e\u043b\u044b\u043f \u0442\u0430\u0431\u044b\u043b\u0430\u0434\u044b.",
     "MediaBrowserHasCommunity": "Media Browser \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440\u044b \u0431\u0435\u043d \u049b\u043e\u043b\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u0434\u044b\u04a3 \u0434\u0430\u043c\u0443\u0434\u0430\u0493\u044b \u049b\u0430\u0443\u044b\u043c\u0434\u0430\u0441\u0442\u044b\u0493\u044b \u0431\u0430\u0440.",
     "MediaBrowserHasCommunity": "Media Browser \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440\u044b \u0431\u0435\u043d \u049b\u043e\u043b\u0434\u0430\u0443\u0448\u044b\u043b\u0430\u0440\u0434\u044b\u04a3 \u0434\u0430\u043c\u0443\u0434\u0430\u0493\u044b \u049b\u0430\u0443\u044b\u043c\u0434\u0430\u0441\u0442\u044b\u0493\u044b \u0431\u0430\u0440.",
-    "HeaderInviteUserHelp": "Sharing your media with friends is easier than ever before with Media Browser Connect.",
+    "HeaderInviteUserHelp": "Media Browser Connect \u0430\u0440\u049b\u044b\u043b\u044b \u0442\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u0434\u043e\u0441\u0442\u0430\u0440\u044b\u04a3\u044b\u0437\u0431\u0435\u043d \u043e\u0440\u0442\u0430\u049b\u0442\u0430\u0441\u0443 \u0431\u04b1\u0440\u044b\u043d\u043d\u0430\u043d \u0434\u0430 \u0436\u0435\u04a3\u0456\u043b\u0434\u0435\u0443 \u0431\u043e\u043b\u0434\u044b.",
     "CheckoutKnowledgeBase": "Media Browser \u0435\u04a3 \u04af\u043b\u043a\u0435\u043d \u049b\u0430\u0439\u0442\u0430\u0440\u044b\u043c\u0434\u044b\u043b\u044b\u0493\u044b\u043d \u0430\u043b\u0443 \u0436\u04e9\u043d\u0456\u043d\u0434\u0435 \u043a\u04e9\u043c\u0435\u043a\u0442\u0435\u0441\u0443 \u04af\u0448\u0456\u043d \u0411\u0456\u043b\u0456\u043c \u049b\u043e\u0440\u044b\u043d \u049b\u0430\u0440\u0430\u043f \u0448\u044b\u0493\u044b\u04a3\u044b\u0437.",
     "CheckoutKnowledgeBase": "Media Browser \u0435\u04a3 \u04af\u043b\u043a\u0435\u043d \u049b\u0430\u0439\u0442\u0430\u0440\u044b\u043c\u0434\u044b\u043b\u044b\u0493\u044b\u043d \u0430\u043b\u0443 \u0436\u04e9\u043d\u0456\u043d\u0434\u0435 \u043a\u04e9\u043c\u0435\u043a\u0442\u0435\u0441\u0443 \u04af\u0448\u0456\u043d \u0411\u0456\u043b\u0456\u043c \u049b\u043e\u0440\u044b\u043d \u049b\u0430\u0440\u0430\u043f \u0448\u044b\u0493\u044b\u04a3\u044b\u0437.",
     "ButtonSendInvitation": "\u0428\u0430\u049b\u044b\u0440\u044b\u043c\u0434\u044b \u0436\u0456\u0431\u0435\u0440\u0443",
     "ButtonSendInvitation": "\u0428\u0430\u049b\u044b\u0440\u044b\u043c\u0434\u044b \u0436\u0456\u0431\u0435\u0440\u0443",
     "SearchKnowledgeBase": "\u0411\u0456\u043b\u0456\u043c \u049b\u043e\u0440\u044b\u043d\u0430\u043d \u0456\u0437\u0434\u0435\u0443",
     "SearchKnowledgeBase": "\u0411\u0456\u043b\u0456\u043c \u049b\u043e\u0440\u044b\u043d\u0430\u043d \u0456\u0437\u0434\u0435\u0443",

+ 7 - 7
MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json

@@ -440,19 +440,19 @@
     "VisitMediaBrowserWebsite": "Visitar o Web Site do Media Browser",
     "VisitMediaBrowserWebsite": "Visitar o Web Site do Media Browser",
     "HeaderPendingInvitations": "Convites pendentes",
     "HeaderPendingInvitations": "Convites pendentes",
     "VisitMediaBrowserWebsiteLong": "Visite o Web Site do Media Browser para obter as \u00faltimas novidades e atualizar-se com o blog de desenvolvedores.",
     "VisitMediaBrowserWebsiteLong": "Visite o Web Site do Media Browser para obter as \u00faltimas novidades e atualizar-se com o blog de desenvolvedores.",
-    "TabParentalControl": "Parental Control",
+    "TabParentalControl": "Controle Parental",
     "OptionHideUser": "Ocultar este usu\u00e1rio das telas de login",
     "OptionHideUser": "Ocultar este usu\u00e1rio das telas de login",
-    "HeaderAccessSchedule": "Access Schedule",
+    "HeaderAccessSchedule": "Agendamento de Acesso",
     "OptionDisableUser": "Desativar este usu\u00e1rio",
     "OptionDisableUser": "Desativar este usu\u00e1rio",
-    "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.",
+    "HeaderAccessScheduleHelp": "Criar um agendamento de acesso para limitar o acesso a certas horas.",
     "OptionDisableUserHelp": "Se estiver desativado o servidor n\u00e3o permitir\u00e1 nenhuma conex\u00e3o deste usu\u00e1rio. Conex\u00f5es existentes ser\u00e3o abruptamente terminadas.",
     "OptionDisableUserHelp": "Se estiver desativado o servidor n\u00e3o permitir\u00e1 nenhuma conex\u00e3o deste usu\u00e1rio. Conex\u00f5es existentes ser\u00e3o abruptamente terminadas.",
-    "ButtonAddSchedule": "Add Schedule",
+    "ButtonAddSchedule": "Adicionar Agendamento",
     "HeaderAdvancedControl": "Controle Avan\u00e7ado",
     "HeaderAdvancedControl": "Controle Avan\u00e7ado",
-    "LabelAccessDay": "Day of week:",
+    "LabelAccessDay": "Dia da semana:",
     "LabelName": "Nome:",
     "LabelName": "Nome:",
-    "LabelAccessStart": "Start hour:",
+    "LabelAccessStart": "Hora inicial:",
     "OptionAllowUserToManageServer": "Permitir a este usu\u00e1rio administrar o servidor",
     "OptionAllowUserToManageServer": "Permitir a este usu\u00e1rio administrar o servidor",
-    "LabelAccessEnd": "End hour:",
+    "LabelAccessEnd": "Hora final:",
     "HeaderFeatureAccess": "Acesso aos Recursos",
     "HeaderFeatureAccess": "Acesso aos Recursos",
     "OptionAllowMediaPlayback": "Permitir reprodu\u00e7\u00e3o de m\u00eddia",
     "OptionAllowMediaPlayback": "Permitir reprodu\u00e7\u00e3o de m\u00eddia",
     "OptionAllowBrowsingLiveTv": "Permitir navega\u00e7\u00e3o na tv ao vivo",
     "OptionAllowBrowsingLiveTv": "Permitir navega\u00e7\u00e3o na tv ao vivo",

+ 3 - 2
MediaBrowser.Server.Implementations/Localization/Server/server.json

@@ -1167,7 +1167,7 @@
     "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan",
     "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan",
     "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.",
     "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.",
     "LabelConnectUserName": "Media Browser username/email:",
     "LabelConnectUserName": "Media Browser username/email:",
-    "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from any app without having to know the server ip address.",
+    "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from Media Browser any app without having to know the server ip address.",
     "ButtonLearnMoreAboutMediaBrowserConnect": "Learn more about Media Browser Connect",
     "ButtonLearnMoreAboutMediaBrowserConnect": "Learn more about Media Browser Connect",
     "LabelExternalPlayers": "External players:",
     "LabelExternalPlayers": "External players:",
     "LabelExternalPlayersHelp": "Display buttons to play content in external players. This is only available on devices that support url schemes, generally Android and iOS. With external players there is generally no support for remote control or resuming.",
     "LabelExternalPlayersHelp": "Display buttons to play content in external players. This is only available on devices that support url schemes, generally Android and iOS. With external players there is generally no support for remote control or resuming.",
@@ -1246,5 +1246,6 @@
     "OptionEveryday": "Every day",
     "OptionEveryday": "Every day",
     "OptionWeekdays": "Weekdays",
     "OptionWeekdays": "Weekdays",
     "OptionWeekends": "Weekends",
     "OptionWeekends": "Weekends",
-    "MessageProfileInfoSynced":  "User profile information synced with Media Browser Connect."
+    "MessageProfileInfoSynced": "User profile information synced with Media Browser Connect.",
+    "HeaderOptionalLinkMediaBrowserAccount": "Optional: Link your Media Browser account"
 }
 }

+ 1229 - 0
MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json

@@ -0,0 +1,1229 @@
+{
+    "LabelExit": "\u79bb\u5f00",
+    "OptionReportAdultVideos": "Adult videos",
+    "LabelVisitCommunity": "\u8bbf\u95ee\u793e\u533a",
+    "ButtonMore": "More",
+    "LabelGithubWiki": "Github\u7ef4\u57fa",
+    "HeaderActivity": "Activity",
+    "LabelSwagger": "Swagger",
+    "ScheduledTaskStartedWithName": "{0} started",
+    "LabelStandard": "\u6807\u51c6",
+    "ScheduledTaskCancelledWithName": "{0} was cancelled",
+    "LabelViewApiDocumentation": "\u67e5\u770bAPi\u6587\u6863",
+    "ScheduledTaskCompletedWithName": "{0} completed",
+    "LabelBrowseLibrary": "\u6d4f\u89c8\u5a92\u4f53\u5e93",
+    "ScheduledTaskFailed": "Scheduled task completed",
+    "LabelConfigureMediaBrowser": "\u914d\u7f6eMedia Browser",
+    "PluginInstalledWithName": "{0} was installed",
+    "LabelOpenLibraryViewer": "\u6253\u5f00\u5a92\u4f53\u5e93\u6d4f\u89c8\u5668",
+    "PluginUpdatedWithName": "{0} was updated",
+    "LabelRestartServer": "\u91cd\u542f\u670d\u52a1\u5668",
+    "PluginUninstalledWithName": "{0} was uninstalled",
+    "LabelShowLogWindow": "\u663e\u793a\u65e5\u5fd7\u7a97\u53e3",
+    "ScheduledTaskFailedWithName": "{0} failed",
+    "LabelPrevious": "\u4e0a\u4e00\u4e2a",
+    "ItemAddedWithName": "{0} was added to the library",
+    "LabelFinish": "\u7ed3\u675f",
+    "ItemRemovedWithName": "{0} was removed from the library",
+    "LabelNext": "\u4e0b\u4e00\u4e2a",
+    "DeviceOnlineWithName": "{0} is connected",
+    "LabelYoureDone": "\u5b8c\u6210\uff01",
+    "UserOnlineFromDevice": "{0} is online from {1}",
+    "WelcomeToMediaBrowser": "\u6b22\u8fce\u8fdb\u5165Media Browser\uff01",
+    "DeviceOfflineWithName": "{0} has disconnected",
+    "TitleMediaBrowser": "Media Browser",
+    "UserOfflineFromDevice": "{0} has disconnected from {1}",
+    "ThisWizardWillGuideYou": "\u8be5\u5411\u5bfc\u5c06\u6307\u5bfc\u4f60\u5b8c\u6210\u5b89\u88c5\u8fc7\u7a0b\u3002\u9996\u5148\uff0c\u8bf7\u9009\u62e9\u4f60\u7684\u8bed\u8a00\u3002",
+    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
+    "TellUsAboutYourself": "\u8bf7\u4ecb\u7ecd\u4e00\u4e0b\u4f60\u81ea\u5df1",
+    "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
+    "LabelYourFirstName": "\u4f60\u7684\u540d\u5b57\uff1a",
+    "LabelRunningTimeValue": "Running time: {0}",
+    "MoreUsersCanBeAddedLater": "\u7a0d\u540e\u5728\u4eea\u8868\u76d8\u4e2d\u53ef\u4ee5\u6dfb\u52a0\u66f4\u591a\u7528\u6237\u3002",
+    "LabelIpAddressValue": "Ip address: {0}",
+    "UserProfilesIntro": "Media Browser\u652f\u6301\u591a\u4e2a\u7528\u6237\u8bbe\u5b9a\uff0c\u80fd\u4f7f\u6bcf\u4e2a\u7528\u6237\u90fd\u62e5\u6709\u81ea\u5df1\u4e13\u5c5e\u7684\u663e\u793a\u8bbe\u7f6e\uff0c\u64ad\u653e\u72b6\u6001\u548c\u5bb6\u957f\u63a7\u5236\u8bbe\u7f6e\u3002",
+    "UserConfigurationUpdatedWithName": "User configuration has been updated for {0}",
+    "LabelWindowsService": "Windows \u670d\u52a1",
+    "UserCreatedWithName": "User {0} has been created",
+    "AWindowsServiceHasBeenInstalled": "Windows \u670d\u52a1\u5b89\u88c5\u5b8c\u6210",
+    "UserPasswordChangedWithName": "Password has been changed for user {0}",
+    "WindowsServiceIntro1": "Media Browser\u670d\u52a1\u5668\u4f5c\u4e3a\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4ee5\u4e00\u4e2a\u6258\u76d8\u56fe\u6807\u8fd0\u884c\uff0c\u4f46\u5982\u679c\u4f60\u559c\u6b22\u5b83\u4f5c\u4e3a\u540e\u53f0\u670d\u52a1\u8fd0\u884c\uff0c\u5b83\u53ef\u4ee5\u4eceWindows\u63a7\u5236\u9762\u677f\u542f\u52a8\u3002",
+    "UserDeletedWithName": "User {0} has been deleted",
+    "WindowsServiceIntro2": "If using the windows service, please note that it cannot be run at the same time as the tray icon, so you'll need to exit the tray in order to run the service. The service will also need to be configured with administrative privileges via the control panel. Please note that at this time the service is unable to self-update, so new versions will require manual interaction.",
+    "MessageServerConfigurationUpdated": "Server configuration has been updated",
+    "WizardCompleted": "That's all we need for now. Media Browser has begun collecting information about your media library. Check out some of our apps, and then click <b>Finish<\/b> to view the <b>Dashboard<\/b>.",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
+    "LabelConfigureSettings": "Configure settings",
+    "MessageApplicationUpdated": "Media Browser Server has been updated",
+    "LabelEnableVideoImageExtraction": "Enable video image extraction",
+    "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
+    "VideoImageExtractionHelp": "For videos that don't already have images, and that we're unable to find internet images for. This will add some additional time to the initial library scan but will result in a more pleasing presentation.",
+    "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
+    "LabelEnableChapterImageExtractionForMovies": "Extract chapter image extraction for Movies",
+    "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
+    "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 at 4am, although this is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.",
+    "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
+    "LabelEnableAutomaticPortMapping": "Enable automatic port mapping",
+    "AppDeviceValues": "App: {0}, Device: {1}",
+    "LabelEnableAutomaticPortMappingHelp": "UPnP allows automated router configuration for easy remote access. This may not work with some router models.",
+    "ProviderValue": "Provider: {0}",
+    "ButtonOk": "Ok",
+    "LabelChannelDownloadSizeLimit": "Download size limit (GB):",
+    "ButtonCancel": "Cancel",
+    "LabelChannelDownloadSizeLimitHelpText": "Limit the size of the channel download folder.",
+    "HeaderRecentActivity": "Recent Activity",
+    "ButtonNew": "New",
+    "HeaderPeople": "People",
+    "HeaderSetupLibrary": "Setup your media library",
+    "HeaderDownloadPeopleMetadataFor": "Download biography and images for:",
+    "ButtonAddMediaFolder": "Add media folder",
+    "OptionComposers": "Composers",
+    "LabelFolderType": "Folder type:",
+    "OptionOthers": "Others",
+    "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.",
+    "ReferToMediaLibraryWiki": "Refer to the media library wiki.",
+    "HeaderDownloadPeopleMetadataForHelp": "Enabling additional options will provide more on-screen information but will result in slower library scans.",
+    "LabelCountry": "Country:",
+    "ViewTypeFolders": "Folders",
+    "LabelLanguage": "Language:",
+    "LabelDisplayFoldersView": "Display a folders view to show plain media folders",
+    "HeaderPreferredMetadataLanguage": "Preferred metadata language:",
+    "ViewTypeLiveTvRecordingGroups": "Recordings",
+    "LabelSaveLocalMetadata": "Save artwork and metadata into media folders",
+    "ViewTypeLiveTvChannels": "Channels",
+    "LabelSaveLocalMetadataHelp": "Saving artwork and metadata directly into media folders will put them in a place where they can be easily edited.",
+    "LabelAllowLocalAccessWithoutPassword": "Allow local access without a password",
+    "LabelDownloadInternetMetadata": "Download artwork and metadata from the internet",
+    "LabelAllowLocalAccessWithoutPasswordHelp": "When enabled, a password will not be required when signing in from within your home network.",
+    "LabelDownloadInternetMetadataHelp": "Media Browser can download information about your media to enable rich presentations.",
+    "HeaderPassword": "Password",
+    "TabPreferences": "Preferences",
+    "HeaderLocalAccess": "Local Access",
+    "TabPassword": "Password",
+    "HeaderViewOrder": "View Order",
+    "TabLibraryAccess": "Library Access",
+    "LabelSelectUserViewOrder": "Choose the order your views will be displayed in within Media Browser apps",
+    "TabImage": "Image",
+    "LabelMetadataRefreshMode": "Metadata refresh mode:",
+    "TabProfile": "Profile",
+    "LabelImageRefreshMode": "Image refresh mode:",
+    "TabMetadata": "Metadata",
+    "OptionDownloadMissingImages": "Download missing images",
+    "TabImages": "Images",
+    "OptionReplaceExistingImages": "Replace existing images",
+    "TabNotifications": "Notifications",
+    "OptionRefreshAllData": "Refresh all data",
+    "TabCollectionTitles": "Titles",
+    "OptionAddMissingDataOnly": "Add missing data only",
+    "LabelDisplayMissingEpisodesWithinSeasons": "Display missing episodes within seasons",
+    "OptionLocalRefreshOnly": "Local refresh only",
+    "LabelUnairedMissingEpisodesWithinSeasons": "Display unaired episodes within seasons",
+    "HeaderRefreshMetadata": "Refresh Metadata",
+    "HeaderVideoPlaybackSettings": "Video Playback Settings",
+    "HeaderPersonInfo": "Person Info",
+    "HeaderPlaybackSettings": "Playback Settings",
+    "HeaderIdentifyItem": "Identify Item",
+    "LabelAudioLanguagePreference": "Audio language preference:",
+    "HeaderIdentifyItemHelp": "Enter one or more search criteria. Remove criteria to increase search results.",
+    "LabelSubtitleLanguagePreference": "Subtitle language preference:",
+    "HeaderConfirmDeletion": "Confirm Deletion",
+    "OptionDefaultSubtitles": "Default",
+    "LabelFollowingFileWillBeDeleted": "The following file will be deleted:",
+    "OptionOnlyForcedSubtitles": "Only forced subtitles",
+    "LabelIfYouWishToContinueWithDeletion": "If you wish to continue, please confirm by entering the value of:",
+    "OptionAlwaysPlaySubtitles": "Always play subtitles",
+    "ButtonIdentify": "Identify",
+    "OptionNoSubtitles": "No Subtitles",
+    "LabelAlbumArtist": "Album artist:",
+    "OptionDefaultSubtitlesHelp": "Subtitles matching the language preference will be loaded when the audio is in a foreign language.",
+    "LabelAlbum": "Album:",
+    "OptionOnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.",
+    "LabelCommunityRating": "Community rating:",
+    "OptionAlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.",
+    "LabelVoteCount": "Vote count:",
+    "OptionNoSubtitlesHelp": "Subtitles will not be loaded by default.",
+    "LabelMetascore": "Metascore:",
+    "TabProfiles": "Profiles",
+    "LabelCriticRating": "Critic rating:",
+    "TabSecurity": "Security",
+    "LabelCriticRatingSummary": "Critic rating summary:",
+    "ButtonAddUser": "Add User",
+    "LabelAwardSummary": "Award summary:",
+    "LabelWebsite": "Website:",
+    "ButtonAddLocalUser": "Add Local User",
+    "LabelTagline": "Tagline:",
+    "ButtonInviteUser": "Invite User",
+    "ButtonSave": "Save",
+    "LabelOverview": "Overview:",
+    "ButtonResetPassword": "Reset Password",
+    "LabelShortOverview": "Short overview:",
+    "LabelNewPassword": "New password:",
+    "LabelReleaseDate": "Release date:",
+    "LabelNewPasswordConfirm": "New password confirm:",
+    "LabelYear": "Year:",
+    "HeaderCreatePassword": "Create Password",
+    "LabelPlaceOfBirth": "Place of birth:",
+    "LabelCurrentPassword": "Current password:",
+    "LabelEndDate": "End date:",
+    "LabelMaxParentalRating": "Maximum allowed parental rating:",
+    "LabelAirDate": "Air days:",
+    "MaxParentalRatingHelp": "Content with a higher rating will be hidden from this user.",
+    "LabelAirTime:": "Air time:",
+    "LibraryAccessHelp": "Select the media folders to share with this user. Administrators will be able to edit all folders using the metadata manager.",
+    "LabelRuntimeMinutes": "Run time (minutes):",
+    "ChannelAccessHelp": "Select the channels to share with this user. Administrators will be able to edit all channels using the metadata manager.",
+    "LabelParentalRating": "Parental rating:",
+    "ButtonDeleteImage": "Delete Image",
+    "LabelCustomRating": "Custom rating:",
+    "LabelSelectUsers": "Select users:",
+    "LabelBudget": "Budget",
+    "ButtonUpload": "Upload",
+    "LabelRevenue": "Revenue ($):",
+    "HeaderUploadNewImage": "Upload New Image",
+    "LabelOriginalAspectRatio": "Original aspect ratio:",
+    "LabelDropImageHere": "Drop image here",
+    "LabelPlayers": "Players:",
+    "ImageUploadAspectRatioHelp": "1:1 Aspect Ratio Recommended. JPG\/PNG only.",
+    "Label3DFormat": "3D format:",
+    "MessageNothingHere": "Nothing here.",
+    "HeaderAlternateEpisodeNumbers": "Alternate Episode Numbers",
+    "MessagePleaseEnsureInternetMetadata": "Please ensure downloading of internet metadata is enabled.",
+    "HeaderSpecialEpisodeInfo": "Special Episode Info",
+    "TabSuggested": "Suggested",
+    "HeaderExternalIds": "External Id's:",
+    "TabLatest": "Latest",
+    "LabelDvdSeasonNumber": "Dvd season number:",
+    "TabUpcoming": "Upcoming",
+    "LabelDvdEpisodeNumber": "Dvd episode number:",
+    "TabShows": "Shows",
+    "LabelAbsoluteEpisodeNumber": "Absolute episode number:",
+    "TabEpisodes": "Episodes",
+    "LabelAirsBeforeSeason": "Airs before season:",
+    "TabGenres": "Genres",
+    "LabelAirsAfterSeason": "Airs after season:",
+    "TabPeople": "People",
+    "LabelAirsBeforeEpisode": "Airs before episode:",
+    "TabNetworks": "Networks",
+    "LabelTreatImageAs": "Treat image as:",
+    "HeaderUsers": "Users",
+    "LabelDisplayOrder": "Display order:",
+    "HeaderFilters": "Filters:",
+    "LabelDisplaySpecialsWithinSeasons": "Display specials within seasons they aired in",
+    "ButtonFilter": "Filter",
+    "HeaderCountries": "Countries",
+    "OptionFavorite": "Favorites",
+    "HeaderGenres": "Genres",
+    "OptionLikes": "Likes",
+    "HeaderPlotKeywords": "Plot Keywords",
+    "OptionDislikes": "Dislikes",
+    "HeaderStudios": "Studios",
+    "OptionActors": "Actors",
+    "HeaderTags": "Tags",
+    "OptionGuestStars": "Guest Stars",
+    "HeaderMetadataSettings": "Metadata Settings",
+    "OptionDirectors": "Directors",
+    "LabelLockItemToPreventChanges": "Lock this item to prevent future changes",
+    "OptionWriters": "Writers",
+    "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item, or the global default value.",
+    "OptionProducers": "Producers",
+    "TabDonate": "Donate",
+    "HeaderResume": "Resume",
+    "HeaderDonationType": "Donation type:",
+    "HeaderNextUp": "Next Up",
+    "OptionMakeOneTimeDonation": "Make a separate donation",
+    "NoNextUpItemsMessage": "None found. Start watching your shows!",
+    "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits and will not produce a supporter key.",
+    "HeaderLatestEpisodes": "Latest Episodes",
+    "OptionLifeTimeSupporterMembership": "Lifetime supporter membership",
+    "HeaderPersonTypes": "Person Types:",
+    "OptionYearlySupporterMembership": "Yearly supporter membership",
+    "TabSongs": "Songs",
+    "OptionMonthlySupporterMembership": "Monthly supporter membership",
+    "TabAlbums": "Albums",
+    "HeaderSupporterBenefit": "A supporter membership provides additional benefits such as access to premium plugins, internet channel content, and more.",
+    "TabArtists": "Artists",
+    "OptionNoTrailer": "No Trailer",
+    "TabAlbumArtists": "Album Artists",
+    "OptionNoThemeSong": "No Theme Song",
+    "TabMusicVideos": "Music Videos",
+    "OptionNoThemeVideo": "No Theme Video",
+    "ButtonSort": "Sort",
+    "LabelOneTimeDonationAmount": "Donation amount:",
+    "HeaderSortBy": "Sort By:",
+    "OptionActor": "Actor",
+    "HeaderSortOrder": "Sort Order:",
+    "OptionComposer": "Composer",
+    "OptionPlayed": "Played",
+    "OptionDirector": "Director",
+    "OptionUnplayed": "Unplayed",
+    "OptionGuestStar": "Guest star",
+    "OptionAscending": "Ascending",
+    "OptionProducer": "Producer",
+    "OptionDescending": "Descending",
+    "OptionWriter": "Writer",
+    "OptionRuntime": "Runtime",
+    "LabelAirDays": "Air days:",
+    "LabelAirTime": "Air time:",
+    "OptionReleaseDate": "Release Date",
+    "OptionPlayCount": "Play Count",
+    "HeaderMediaInfo": "Media Info",
+    "OptionDatePlayed": "Date Played",
+    "HeaderPhotoInfo": "Photo Info",
+    "OptionDateAdded": "Date Added",
+    "HeaderInstall": "Install",
+    "OptionAlbumArtist": "Album Artist",
+    "LabelSelectVersionToInstall": "Select version to install:",
+    "OptionArtist": "Artist",
+    "LinkSupporterMembership": "Learn about the Supporter Membership",
+    "OptionAlbum": "Album",
+    "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
+    "OptionTrackName": "Track Name",
+    "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
+    "OptionCommunityRating": "Community Rating",
+    "HeaderReviews": "Reviews",
+    "OptionNameSort": "Name",
+    "HeaderDeveloperInfo": "Developer Info",
+    "OptionFolderSort": "Folders",
+    "HeaderRevisionHistory": "Revision History",
+    "OptionBudget": "Budget",
+    "ButtonViewWebsite": "View website",
+    "OptionRevenue": "Revenue",
+    "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
+    "OptionPoster": "Poster",
+    "HeaderXmlSettings": "Xml Settings",
+    "OptionBackdrop": "Backdrop",
+    "HeaderXmlDocumentAttributes": "Xml Document Attributes",
+    "OptionTimeline": "Timeline",
+    "HeaderXmlDocumentAttribute": "Xml Document Attribute",
+    "OptionThumb": "Thumb",
+    "XmlDocumentAttributeListHelp": "These attributes are applied to the root element of every xml response.",
+    "OptionBanner": "Banner",
+    "OptionSaveMetadataAsHidden": "Save metadata and images as hidden files",
+    "OptionCriticRating": "Critic Rating",
+    "LabelExtractChaptersDuringLibraryScan": "Extract chapter images during the library scan",
+    "OptionVideoBitrate": "Video Bitrate",
+    "LabelExtractChaptersDuringLibraryScanHelp": "If enabled, chapter images will be extracted when videos are imported during the library scan. If disabled they will be extracted during the chapter images scheduled task, allowing the regular library scan to complete faster.",
+    "OptionResumable": "Resumable",
+    "LabelConnectUserName": "Media Browser username\/email:",
+    "ScheduledTasksHelp": "Click a task to adjust its schedule.",
+    "LabelConnectUserNameHelp": "Connect this user to a Media Browser account to enable easy sign-in access from any app without having to know the server ip address.",
+    "ScheduledTasksTitle": "Scheduled Tasks",
+    "ButtonLearnMoreAboutMediaBrowserConnect": "Learn more about Media Browser Connect",
+    "TabMyPlugins": "My Plugins",
+    "LabelExternalPlayers": "External players:",
+    "TabCatalog": "Catalog",
+    "LabelExternalPlayersHelp": "Display buttons to play content in external players. This is only available on devices that support url schemes, generally Android and iOS. With external players there is generally no support for remote control or resuming.",
+    "HeaderSubtitleProfile": "Subtitle Profile",
+    "PluginsTitle": "Plugins",
+    "HeaderAutomaticUpdates": "Automatic Updates",
+    "HeaderSubtitleProfiles": "Subtitle Profiles",
+    "HeaderSubtitleProfilesHelp": "Subtitle profiles describe the subtitle formats supported by the device.",
+    "HeaderNowPlaying": "Now Playing",
+    "LabelFormat": "Format:",
+    "HeaderLatestAlbums": "Latest Albums",
+    "LabelMethod": "Method:",
+    "HeaderLatestSongs": "Latest Songs",
+    "LabelDidlMode": "Didl mode:",
+    "HeaderRecentlyPlayed": "Recently Played",
+    "OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)",
+    "HeaderFrequentlyPlayed": "Frequently Played",
+    "OptionResElement": "res element",
+    "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.",
+    "OptionEmbedSubtitles": "Embed within container",
+    "LabelVideoType": "Video Type:",
+    "OptionExternallyDownloaded": "External download",
+    "OptionBluray": "Bluray",
+    "OptionHlsSegmentedSubtitles": "Hls segmented subtitles",
+    "OptionDvd": "Dvd",
+    "OptionIso": "Iso",
+    "LabelSubtitleFormatHelp": "Example: srt",
+    "Option3D": "3D",
+    "ButtonLearnMore": "Learn more",
+    "LabelFeatures": "Features:",
+    "TabPlayback": "Playback",
+    "LabelService": "Service:",
+    "HeaderTrailersAndExtras": "Trailers & Extras",
+    "LabelStatus": "Status:",
+    "OptionFindTrailers": "Find trailers from the internet automatically",
+    "LabelVersion": "Version:",
+    "HeaderLanguagePreferences": "Language Preferences",
+    "LabelLastResult": "Last result:",
+    "TabCinemaMode": "Cinema Mode",
+    "OptionHasSubtitles": "Subtitles",
+    "TitlePlayback": "Playback",
+    "OptionHasTrailer": "Trailer",
+    "LabelEnableCinemaModeFor": "Enable cinema mode for:",
+    "OptionHasThemeSong": "Theme Song",
+    "CinemaModeConfigurationHelp": "Cinema mode brings the theater experience straight to your living room with the ability to play trailers and custom intros before the main feature.",
+    "OptionHasThemeVideo": "Theme Video",
+    "OptionTrailersFromMyMovies": "Include trailers from movies in my library",
+    "TabMovies": "Movies",
+    "OptionUpcomingMoviesInTheaters": "Include trailers from new and upcoming movies",
+    "TabStudios": "Studios",
+    "LabelLimitIntrosToUnwatchedContent": "Only use trailers from unwatched content",
+    "TabTrailers": "Trailers",
+    "LabelEnableIntroParentalControl": "Enable smart parental control",
+    "LabelArtists": "Artists:",
+    "LabelEnableIntroParentalControlHelp": "Trailers will only be selected with a parental rating equal to or less than the content being watched.",
+    "LabelArtistsHelp": "Separate multiple using ;",
+    "LabelTheseFeaturesRequireSupporterHelpAndTrailers": "These features require an active supporter membership and installation of the Trailer channel plugin.",
+    "HeaderLatestMovies": "Latest Movies",
+    "OptionTrailersFromMyMoviesHelp": "Requires setup of local trailers.",
+    "HeaderLatestTrailers": "Latest Trailers",
+    "LabelCustomIntrosPath": "Custom intros path:",
+    "OptionHasSpecialFeatures": "Special Features",
+    "LabelCustomIntrosPathHelp": "A folder containing video files. A video will be randomly selected and played after trailers.",
+    "OptionImdbRating": "IMDb Rating",
+    "ValueSpecialEpisodeName": "Special - {0}",
+    "OptionParentalRating": "Parental Rating",
+    "LabelSelectInternetTrailersForCinemaMode": "Internet trailers:",
+    "OptionPremiereDate": "Premiere Date",
+    "OptionUpcomingDvdMovies": "Include trailers from new and upcoming movies on Dvd & Blu-ray",
+    "TabBasic": "Basic",
+    "OptionUpcomingStreamingMovies": "Include trailers from new and upcoming movies on Netflix",
+    "TabAdvanced": "Advanced",
+    "LabelDisplayTrailersWithinMovieSuggestions": "Display trailers within movie suggestions",
+    "HeaderStatus": "Status",
+    "LabelDisplayTrailersWithinMovieSuggestionsHelp": "Requires installation of the Trailer channel.",
+    "OptionContinuing": "Continuing",
+    "CinemaModeConfigurationHelp2": "Individual users will have the ability to disable cinema mode within their own preferences.",
+    "OptionEnded": "Ended",
+    "LabelEnableCinemaMode": "Enable cinema mode",
+    "HeaderAirDays": "Air Days",
+    "HeaderCinemaMode": "Cinema Mode",
+    "OptionSunday": "Sunday",
+    "HeaderWelcomeToMediaBrowserServerDashboard": "Welcome to the Media Browser Dashboard",
+    "OptionMonday": "Monday",
+    "LabelDateAddedBehavior": "Date added behavior for new content:",
+    "OptionTuesday": "Tuesday",
+    "OptionDateAddedImportTime": "Use date scanned into the library",
+    "OptionWednesday": "Wednesday",
+    "OptionDateAddedFileTime": "Use file creation date",
+    "OptionThursday": "Thursday",
+    "LabelDateAddedBehaviorHelp": "If a metadata value is present it will always be used before either of these options.",
+    "OptionFriday": "Friday",
+    "LabelNumberTrailerToPlay": "Number of trailers to play:",
+    "OptionSaturday": "Saturday",
+    "TitleDevices": "Devices",
+    "HeaderManagement": "Management",
+    "TabCameraUpload": "Camera Upload",
+    "LabelManagement": "Management:",
+    "TabDevices": "Devices",
+    "OptionMissingImdbId": "Missing IMDb Id",
+    "HeaderCameraUploadHelp": "Automatically upload photos and videos taken from your mobile devices into Media Browser.",
+    "OptionMissingTvdbId": "Missing TheTVDB Id",
+    "MessageNoDevicesSupportCameraUpload": "You currently don't have any devices that support camera upload.",
+    "OptionMissingOverview": "Missing Overview",
+    "LabelCameraUploadPath": "Camera upload path:",
+    "OptionFileMetadataYearMismatch": "File\/Metadata Years Mismatched",
+    "LabelCameraUploadPathHelp": "Select a custom upload path, if desired. If unspecified a default folder will be used.",
+    "TabGeneral": "General",
+    "LabelCreateCameraUploadSubfolder": "Create a subfolder for each device",
+    "TitleSupport": "Support",
+    "LabelCreateCameraUploadSubfolderHelp": "Specific folders can be assigned to a device by clicking on it from the Devices page.",
+    "TabLog": "Log",
+    "LabelCustomDeviceDisplayName": "Display name:",
+    "TabAbout": "About",
+    "LabelCustomDeviceDisplayNameHelp": "Supply a custom display name or leave empty to use the name reported by the device.",
+    "TabSupporterKey": "Supporter Key",
+    "HeaderInviteUser": "Invite User",
+    "TabBecomeSupporter": "Become a Supporter",
+    "LabelConnectInviteUserHelp": "This is the username or email that your friend uses to sign in to the Media Browser website.",
+    "MediaBrowserHasCommunity": "Media Browser has a thriving community of users and contributors.",
+    "HeaderInviteUserHelp": "Sharing your media with friends is easier than ever before with Media Browser Connect.",
+    "CheckoutKnowledgeBase": "Check out our knowledge base to help you get the most out of Media Browser.",
+    "ButtonSendInvitation": "Send Invitation",
+    "SearchKnowledgeBase": "Search the Knowledge Base",
+    "HeaderGuests": "Guests",
+    "VisitTheCommunity": "Visit the Community",
+    "HeaderLocalUsers": "Local Users",
+    "VisitMediaBrowserWebsite": "Visit the Media Browser Web Site",
+    "HeaderPendingInvitations": "Pending Invitations",
+    "VisitMediaBrowserWebsiteLong": "Visit the Media Browser Web site to catch the latest news and keep up with the developer blog.",
+    "TabParentalControl": "Parental Control",
+    "OptionHideUser": "Hide this user from login screens",
+    "HeaderAccessSchedule": "Access Schedule",
+    "OptionDisableUser": "Disable this user",
+    "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.",
+    "OptionDisableUserHelp": "If disabled the server will not allow any connections from this user. Existing connections will be abruptly terminated.",
+    "ButtonAddSchedule": "Add Schedule",
+    "HeaderAdvancedControl": "Advanced Control",
+    "LabelAccessDay": "Day of week:",
+    "LabelName": "Name:",
+    "LabelAccessStart": "Start hour:",
+    "OptionAllowUserToManageServer": "Allow this user to manage the server",
+    "LabelAccessEnd": "End hour:",
+    "HeaderFeatureAccess": "Feature Access",
+    "OptionAllowMediaPlayback": "Allow media playback",
+    "OptionAllowBrowsingLiveTv": "Allow browsing of live tv",
+    "OptionAllowDeleteLibraryContent": "Allow this user to delete library content",
+    "OptionAllowManageLiveTv": "Allow management of live tv recordings",
+    "OptionAllowRemoteControlOthers": "Allow this user to remote control other users",
+    "OptionMissingTmdbId": "Missing Tmdb Id",
+    "OptionIsHD": "HD",
+    "OptionIsSD": "SD",
+    "OptionMetascore": "Metascore",
+    "ButtonSelect": "Select",
+    "ButtonGroupVersions": "Group Versions",
+    "ButtonAddToCollection": "Add to Collection",
+    "PismoMessage": "Utilizing Pismo File Mount through a donated license.",
+    "TangibleSoftwareMessage": "Utilizing Tangible Solutions Java\/C# converters through a donated license.",
+    "HeaderCredits": "Credits",
+    "PleaseSupportOtherProduces": "Please support other free products we utilize:",
+    "VersionNumber": "Version {0}",
+    "TabPaths": "Paths",
+    "TabServer": "Server",
+    "TabTranscoding": "Transcoding",
+    "TitleAdvanced": "Advanced",
+    "LabelAutomaticUpdateLevel": "Automatic update level",
+    "OptionRelease": "\u5b98\u65b9\u6b63\u5f0f\u7248",
+    "OptionBeta": "\u6d4b\u8bd5\u7248",
+    "OptionDev": "\u5f00\u53d1\u7248\uff08\u4e0d\u7a33\u5b9a\uff09",
+    "LabelAllowServerAutoRestart": "Allow the server to restart automatically to apply updates",
+    "LabelAllowServerAutoRestartHelp": "The server will only restart during idle periods, when no users are active.",
+    "LabelEnableDebugLogging": "Enable debug logging",
+    "LabelRunServerAtStartup": "Run server at startup",
+    "LabelRunServerAtStartupHelp": "This will start the tray icon on windows startup. To start the windows service, uncheck this and run the service from the windows control panel. Please note that you cannot run both at the same time, so you will need to exit the tray icon before starting the service.",
+    "ButtonSelectDirectory": "Select Directory",
+    "LabelCustomPaths": "Specify custom paths where desired. Leave fields empty to use the defaults.",
+    "LabelCachePath": "Cache path:",
+    "LabelCachePathHelp": "Specify a custom location for server cache files, such as images.",
+    "LabelImagesByNamePath": "Images by name path:",
+    "LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, artist, genre and studio images.",
+    "LabelMetadataPath": "Metadata path:",
+    "LabelMetadataPathHelp": "Specify a custom location for downloaded artwork and metadata, if not saving within media folders.",
+    "LabelTranscodingTempPath": "Transcoding temporary path:",
+    "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder. Specify a custom path, or leave empty to use the default within the server's data folder.",
+    "TabBasics": "Basics",
+    "TabTV": "TV",
+    "TabGames": "Games",
+    "TabMusic": "Music",
+    "TabOthers": "Others",
+    "HeaderExtractChapterImagesFor": "Extract chapter images for:",
+    "OptionMovies": "Movies",
+    "OptionEpisodes": "Episodes",
+    "OptionOtherVideos": "Other Videos",
+    "TitleMetadata": "Metadata",
+    "LabelAutomaticUpdatesFanart": "Enable automatic updates from FanArt.tv",
+    "LabelAutomaticUpdatesTmdb": "Enable automatic updates from TheMovieDB.org",
+    "LabelAutomaticUpdatesTvdb": "Enable automatic updates from TheTVDB.com",
+    "LabelAutomaticUpdatesFanartHelp": "If enabled, new images will be downloaded automatically as they're added to fanart.tv. Existing images will not be replaced.",
+    "LabelAutomaticUpdatesTmdbHelp": "If enabled, new images will be downloaded automatically as they're added to TheMovieDB.org. Existing images will not be replaced.",
+    "LabelAutomaticUpdatesTvdbHelp": "If enabled, new images will be downloaded automatically as they're added to TheTVDB.com. Existing images will not be replaced.",
+    "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 at 4am. The schedule is configurable in the scheduled tasks area. It is not recommended to run this task during peak usage hours.",
+    "LabelMetadataDownloadLanguage": "Preferred download language:",
+    "ButtonAutoScroll": "Auto-scroll",
+    "LabelImageSavingConvention": "Image saving convention:",
+    "LabelImageSavingConventionHelp": "Media Browser recognizes images from most major media applications. Choosing your downloading convention is useful if you also use other products.",
+    "OptionImageSavingCompatible": "Compatible - Media Browser\/Kodi\/Plex",
+    "OptionImageSavingStandard": "Standard - MB2",
+    "ButtonSignIn": "Sign In",
+    "TitleSignIn": "Sign In",
+    "HeaderPleaseSignIn": "Please sign in",
+    "LabelUser": "User:",
+    "LabelPassword": "Password:",
+    "ButtonManualLogin": "Manual Login",
+    "PasswordLocalhostMessage": "Passwords are not required when logging in from localhost.",
+    "TabGuide": "Guide",
+    "TabChannels": "Channels",
+    "TabCollections": "Collections",
+    "HeaderChannels": "Channels",
+    "TabRecordings": "Recordings",
+    "TabScheduled": "Scheduled",
+    "TabSeries": "Series",
+    "TabFavorites": "Favorites",
+    "TabMyLibrary": "My Library",
+    "ButtonCancelRecording": "Cancel Recording",
+    "HeaderPrePostPadding": "Pre\/Post Padding",
+    "LabelPrePaddingMinutes": "Pre-padding minutes:",
+    "OptionPrePaddingRequired": "Pre-padding is required in order to record.",
+    "LabelPostPaddingMinutes": "Post-padding minutes:",
+    "OptionPostPaddingRequired": "Post-padding is required in order to record.",
+    "HeaderWhatsOnTV": "What's On",
+    "HeaderUpcomingTV": "Upcoming TV",
+    "TabStatus": "Status",
+    "TabSettings": "Settings",
+    "ButtonRefreshGuideData": "Refresh Guide Data",
+    "ButtonRefresh": "Refresh",
+    "ButtonAdvancedRefresh": "Advanced Refresh",
+    "OptionPriority": "Priority",
+    "OptionRecordOnAllChannels": "Record program on all channels",
+    "OptionRecordAnytime": "Record program at any time",
+    "OptionRecordOnlyNewEpisodes": "Record only new episodes",
+    "HeaderDays": "Days",
+    "HeaderActiveRecordings": "Active Recordings",
+    "HeaderLatestRecordings": "Latest Recordings",
+    "HeaderAllRecordings": "All Recordings",
+    "ButtonPlay": "Play",
+    "ButtonEdit": "Edit",
+    "ButtonRecord": "Record",
+    "ButtonDelete": "Delete",
+    "ButtonRemove": "Remove",
+    "OptionRecordSeries": "Record Series",
+    "HeaderDetails": "Details",
+    "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",
+    "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:",
+    "OptionDownloadThumbImage": "Thumb",
+    "OptionDownloadMenuImage": "Menu",
+    "OptionDownloadLogoImage": "Logo",
+    "OptionDownloadBoxImage": "Box",
+    "OptionDownloadDiscImage": "Disc",
+    "OptionDownloadBannerImage": "Banner",
+    "OptionDownloadBackImage": "Back",
+    "OptionDownloadArtImage": "Art",
+    "OptionDownloadPrimaryImage": "Primary",
+    "HeaderFetchImages": "Fetch Images:",
+    "HeaderImageSettings": "Image Settings",
+    "TabOther": "Other",
+    "LabelMaxBackdropsPerItem": "Maximum number of backdrops per item:",
+    "LabelMaxScreenshotsPerItem": "Maximum number of screenshots per item:",
+    "LabelMinBackdropDownloadWidth": "Minimum backdrop download width:",
+    "LabelMinScreenshotDownloadWidth": "Minimum screenshot download width:",
+    "ButtonAddScheduledTaskTrigger": "Add Task Trigger",
+    "HeaderAddScheduledTaskTrigger": "Add Task Trigger",
+    "ButtonAdd": "Add",
+    "LabelTriggerType": "Trigger Type:",
+    "OptionDaily": "Daily",
+    "OptionWeekly": "Weekly",
+    "OptionOnInterval": "On an interval",
+    "OptionOnAppStartup": "On application startup",
+    "OptionAfterSystemEvent": "After a system event",
+    "LabelDay": "Day:",
+    "LabelTime": "Time:",
+    "LabelEvent": "Event:",
+    "OptionWakeFromSleep": "Wake from sleep",
+    "LabelEveryXMinutes": "Every:",
+    "HeaderTvTuners": "Tuners",
+    "HeaderGallery": "Gallery",
+    "HeaderLatestGames": "Latest Games",
+    "HeaderRecentlyPlayedGames": "Recently Played Games",
+    "TabGameSystems": "Game Systems",
+    "TitleMediaLibrary": "Media Library",
+    "TabFolders": "Folders",
+    "TabPathSubstitution": "Path Substitution",
+    "LabelSeasonZeroDisplayName": "Season 0 display name:",
+    "LabelEnableRealtimeMonitor": "Enable real time monitoring",
+    "LabelEnableRealtimeMonitorHelp": "Changes will be processed immediately, on supported file systems.",
+    "ButtonScanLibrary": "Scan Library",
+    "HeaderNumberOfPlayers": "Players:",
+    "OptionAnyNumberOfPlayers": "Any",
+    "Option1Player": "1+",
+    "Option2Player": "2+",
+    "Option3Player": "3+",
+    "Option4Player": "4+",
+    "HeaderMediaFolders": "Media Folders",
+    "HeaderThemeVideos": "Theme Videos",
+    "HeaderThemeSongs": "Theme Songs",
+    "HeaderScenes": "Scenes",
+    "HeaderAwardsAndReviews": "Awards and Reviews",
+    "HeaderSoundtracks": "Soundtracks",
+    "HeaderMusicVideos": "Music Videos",
+    "HeaderSpecialFeatures": "Special Features",
+    "HeaderCastCrew": "Cast & Crew",
+    "HeaderAdditionalParts": "Additional Parts",
+    "ButtonSplitVersionsApart": "Split Versions Apart",
+    "ButtonPlayTrailer": "Trailer",
+    "LabelMissing": "Missing",
+    "LabelOffline": "Offline",
+    "PathSubstitutionHelp": "Path substitutions are used for mapping a path on the server to a path that clients are able to access. By allowing clients direct access to media on the server they may be able to play them directly over the network and avoid using server resources to stream and transcode them.",
+    "HeaderFrom": "From",
+    "HeaderTo": "To",
+    "LabelFrom": "From:",
+    "LabelFromHelp": "Example: D:\\Movies (on the server)",
+    "LabelTo": "To:",
+    "LabelToHelp": "Example: \\\\MyServer\\Movies (a path clients can access)",
+    "ButtonAddPathSubstitution": "Add Substitution",
+    "OptionSpecialEpisode": "Specials",
+    "OptionMissingEpisode": "Missing Episodes",
+    "OptionUnairedEpisode": "Unaired Episodes",
+    "OptionEpisodeSortName": "Episode Sort Name",
+    "OptionSeriesSortName": "Series Name",
+    "OptionTvdbRating": "Tvdb Rating",
+    "HeaderTranscodingQualityPreference": "Transcoding Quality Preference:",
+    "OptionAutomaticTranscodingHelp": "The server will decide quality and speed",
+    "OptionHighSpeedTranscodingHelp": "Lower quality, but faster encoding",
+    "OptionHighQualityTranscodingHelp": "Higher quality, but slower encoding",
+    "OptionMaxQualityTranscodingHelp": "Best quality with slower encoding and high CPU usage",
+    "OptionHighSpeedTranscoding": "Higher speed",
+    "OptionHighQualityTranscoding": "Higher quality",
+    "OptionMaxQualityTranscoding": "Max quality",
+    "OptionEnableDebugTranscodingLogging": "Enable debug transcoding logging",
+    "OptionEnableDebugTranscodingLoggingHelp": "This will create very large log files and is only recommended as needed for troubleshooting purposes.",
+    "OptionUpscaling": "Allow clients to request upscaled video",
+    "OptionUpscalingHelp": "In some cases this will result in improved video quality but will increase CPU usage.",
+    "EditCollectionItemsHelp": "Add or remove any movies, series, albums, books or games you wish to group within this collection.",
+    "HeaderAddTitles": "Add Titles",
+    "LabelEnableDlnaPlayTo": "Enable DLNA Play To",
+    "LabelEnableDlnaPlayToHelp": "Media Browser can detect devices within your network and offer the ability to remote control them.",
+    "LabelEnableDlnaDebugLogging": "Enable DLNA debug logging",
+    "LabelEnableDlnaDebugLoggingHelp": "This will create large log files and should only be used as needed for troubleshooting purposes.",
+    "LabelEnableDlnaClientDiscoveryInterval": "Client discovery interval (seconds)",
+    "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determines the duration in seconds between SSDP searches performed by Media Browser.",
+    "HeaderCustomDlnaProfiles": "Custom Profiles",
+    "HeaderSystemDlnaProfiles": "System Profiles",
+    "CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.",
+    "SystemDlnaProfilesHelp": "System profiles are read-only. Changes to a system profile will be saved to a new custom profile.",
+    "TitleDashboard": "Dashboard",
+    "TabHome": "Home",
+    "TabInfo": "Info",
+    "HeaderLinks": "Links",
+    "HeaderSystemPaths": "System Paths",
+    "LinkCommunity": "Community",
+    "LinkGithub": "Github",
+    "LinkApiDocumentation": "Api Documentation",
+    "LabelFriendlyServerName": "Friendly server name:",
+    "LabelFriendlyServerNameHelp": "This name will be used to identify this server. If left blank, the computer name will be used.",
+    "LabelPreferredDisplayLanguage": "Preferred display language",
+    "LabelPreferredDisplayLanguageHelp": "Translating Media Browser is an ongoing project and is not yet complete.",
+    "LabelReadHowYouCanContribute": "Read about how you can contribute.",
+    "HeaderNewCollection": "New Collection",
+    "HeaderAddToCollection": "Add to Collection",
+    "ButtonSubmit": "Submit",
+    "NewCollectionNameExample": "Example: Star Wars Collection",
+    "OptionSearchForInternetMetadata": "Search the internet for artwork and metadata",
+    "ButtonCreate": "Create",
+    "LabelLocalHttpServerPortNumber": "Local port number:",
+    "LabelLocalHttpServerPortNumberHelp": "The tcp port number that Media Browser's http server should bind to.",
+    "LabelPublicPort": "Public port number:",
+    "LabelPublicPortHelp": "The public port number that should be mapped to the local port.",
+    "LabelWebSocketPortNumber": "Web socket port number:",
+    "LabelEnableAutomaticPortMap": "Enable automatic port mapping",
+    "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models.",
+    "LabelExternalDDNS": "External DDNS:",
+    "LabelExternalDDNSHelp": "If you have a dynamic DNS enter it here. Media Browser apps will use it when connecting remotely.",
+    "TabResume": "Resume",
+    "TabWeather": "Weather",
+    "TitleAppSettings": "App Settings",
+    "LabelMinResumePercentage": "Min resume percentage:",
+    "LabelMaxResumePercentage": "Max resume percentage:",
+    "LabelMinResumeDuration": "Min resume duration (seconds):",
+    "LabelMinResumePercentageHelp": "Titles are assumed unplayed if stopped before this time",
+    "LabelMaxResumePercentageHelp": "Titles are assumed fully played if stopped after this time",
+    "LabelMinResumeDurationHelp": "Titles shorter than this will not be resumable",
+    "TitleAutoOrganize": "Auto-Organize",
+    "TabActivityLog": "Activity Log",
+    "HeaderName": "Name",
+    "HeaderDate": "Date",
+    "HeaderSource": "Source",
+    "HeaderDestination": "Destination",
+    "HeaderProgram": "Program",
+    "HeaderClients": "Clients",
+    "LabelCompleted": "Completed",
+    "LabelFailed": "Failed",
+    "LabelSkipped": "Skipped",
+    "HeaderEpisodeOrganization": "Episode Organization",
+    "LabelSeries": "Series:",
+    "LabelSeasonNumber": "Season number:",
+    "LabelEpisodeNumber": "Episode number:",
+    "LabelEndingEpisodeNumber": "Ending episode number:",
+    "LabelEndingEpisodeNumberHelp": "Only required for multi-episode files",
+    "HeaderSupportTheTeam": "Support the Media Browser Team",
+    "LabelSupportAmount": "Amount (USD)",
+    "HeaderSupportTheTeamHelp": "Help ensure the continued development of this project by donating. A portion of all donations will be contributed to other free tools we depend on.",
+    "ButtonEnterSupporterKey": "Enter supporter key",
+    "DonationNextStep": "Once complete, please return and enter your supporter key, which you will receive by email.",
+    "AutoOrganizeHelp": "Auto-organize monitors your download folders for new files and moves them to your media directories.",
+    "AutoOrganizeTvHelp": "TV file organizing will only add episodes to existing series. It will not create new series folders.",
+    "OptionEnableEpisodeOrganization": "Enable new episode organization",
+    "LabelWatchFolder": "Watch folder:",
+    "LabelWatchFolderHelp": "The server will poll this folder during the 'Organize new media files' scheduled task.",
+    "ButtonViewScheduledTasks": "View scheduled tasks",
+    "LabelMinFileSizeForOrganize": "Minimum file size (MB):",
+    "LabelMinFileSizeForOrganizeHelp": "Files under this size will be ignored.",
+    "LabelSeasonFolderPattern": "Season folder pattern:",
+    "LabelSeasonZeroFolderName": "Season zero folder name:",
+    "HeaderEpisodeFilePattern": "Episode file pattern",
+    "LabelEpisodePattern": "Episode pattern:",
+    "LabelMultiEpisodePattern": "Multi-Episode pattern:",
+    "HeaderSupportedPatterns": "Supported Patterns",
+    "HeaderTerm": "Term",
+    "HeaderPattern": "Pattern",
+    "HeaderResult": "Result",
+    "LabelDeleteEmptyFolders": "Delete empty folders after organizing",
+    "LabelDeleteEmptyFoldersHelp": "Enable this to keep the download directory clean.",
+    "LabelDeleteLeftOverFiles": "Delete left over files with the following extensions:",
+    "LabelDeleteLeftOverFilesHelp": "Separate with ;. For example: .nfo;.txt",
+    "OptionOverwriteExistingEpisodes": "Overwrite existing episodes",
+    "LabelTransferMethod": "Transfer method",
+    "OptionCopy": "Copy",
+    "OptionMove": "Move",
+    "LabelTransferMethodHelp": "Copy or move files from the watch folder",
+    "HeaderLatestNews": "Latest News",
+    "HeaderHelpImproveMediaBrowser": "Help Improve Media Browser",
+    "HeaderRunningTasks": "Running Tasks",
+    "HeaderActiveDevices": "Active Devices",
+    "HeaderPendingInstallations": "Pending Installations",
+    "HeaerServerInformation": "Server Information",
+    "ButtonRestartNow": "Restart Now",
+    "ButtonRestart": "Restart",
+    "ButtonShutdown": "Shutdown",
+    "ButtonUpdateNow": "Update Now",
+    "PleaseUpdateManually": "Please shutdown the server and update manually.",
+    "NewServerVersionAvailable": "A new version of Media Browser Server is available!",
+    "ServerUpToDate": "Media Browser Server is up to date",
+    "ErrorConnectingToMediaBrowserRepository": "There was an error connecting to the remote Media Browser repository.",
+    "LabelComponentsUpdated": "The following components have been installed or updated:",
+    "MessagePleaseRestartServerToFinishUpdating": "Please restart the server to finish applying updates.",
+    "LabelDownMixAudioScale": "Audio boost when downmixing:",
+    "LabelDownMixAudioScaleHelp": "Boost audio when downmixing. Set to 1 to preserve original volume value.",
+    "ButtonLinkKeys": "Link Keys",
+    "LabelOldSupporterKey": "Old supporter key",
+    "LabelNewSupporterKey": "New supporter key",
+    "HeaderMultipleKeyLinking": "Multiple Key Linking",
+    "MultipleKeyLinkingHelp": "If you have more than one supporter key, use this form to link the old key's registrations with your new one.",
+    "LabelCurrentEmailAddress": "Current email address",
+    "LabelCurrentEmailAddressHelp": "The current email address to which your new key was sent.",
+    "HeaderForgotKey": "Forgot Key",
+    "LabelEmailAddress": "Email address",
+    "LabelSupporterEmailAddress": "The email address that was used to purchase the key.",
+    "ButtonRetrieveKey": "Retrieve Key",
+    "LabelSupporterKey": "Supporter Key (paste from email)",
+    "LabelSupporterKeyHelp": "Enter your supporter key to start enjoying additional benefits the community has developed for Media Browser.",
+    "MessageInvalidKey": "Supporter key is missing or invalid.",
+    "ErrorMessageInvalidKey": "In order for any premium content to be registered, you must also be a Media Browser Supporter. Please donate and support the continued development of the core product. Thank you.",
+    "HeaderDisplaySettings": "Display Settings",
+    "TabPlayTo": "Play To",
+    "LabelEnableDlnaServer": "Enable Dlna server",
+    "LabelEnableDlnaServerHelp": "Allows UPnP devices on your network to browse and play Media Browser content.",
+    "LabelEnableBlastAliveMessages": "Blast alive messages",
+    "LabelEnableBlastAliveMessagesHelp": "Enable this if the server is not detected reliably by other UPnP devices on your network.",
+    "LabelBlastMessageInterval": "Alive message interval (seconds)",
+    "LabelBlastMessageIntervalHelp": "Determines the duration in seconds between server alive messages.",
+    "LabelDefaultUser": "Default user:",
+    "LabelDefaultUserHelp": "Determines which user library should be displayed on connected devices. This can be overridden for each device using profiles.",
+    "TitleDlna": "DLNA",
+    "TitleChannels": "Channels",
+    "HeaderServerSettings": "Server Settings",
+    "LabelWeatherDisplayLocation": "Weather display location:",
+    "LabelWeatherDisplayLocationHelp": "US zip code \/ City, State, Country \/ City, Country",
+    "LabelWeatherDisplayUnit": "Weather display unit:",
+    "OptionCelsius": "Celsius",
+    "OptionFahrenheit": "Fahrenheit",
+    "HeaderRequireManualLogin": "Require manual username entry for:",
+    "HeaderRequireManualLoginHelp": "When disabled clients may present a login screen with a visual selection of users.",
+    "OptionOtherApps": "Other apps",
+    "OptionMobileApps": "Mobile apps",
+    "HeaderNotificationList": "Click on a notification to configure it's sending options.",
+    "NotificationOptionApplicationUpdateAvailable": "Application update available",
+    "NotificationOptionApplicationUpdateInstalled": "Application update installed",
+    "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
+    "NotificationOptionPluginInstalled": "Plugin installed",
+    "NotificationOptionPluginUninstalled": "Plugin uninstalled",
+    "NotificationOptionVideoPlayback": "Video playback started",
+    "NotificationOptionAudioPlayback": "Audio playback started",
+    "NotificationOptionGamePlayback": "Game playback started",
+    "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
+    "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
+    "NotificationOptionGamePlaybackStopped": "Game playback stopped",
+    "NotificationOptionTaskFailed": "Scheduled task failure",
+    "NotificationOptionInstallationFailed": "Installation failure",
+    "NotificationOptionNewLibraryContent": "New content added",
+    "NotificationOptionNewLibraryContentMultiple": "New content added (multiple)",
+    "SendNotificationHelp": "By default, notifications are delivered to the dashboard inbox. Browse the plugin catalog to install additional notification options.",
+    "NotificationOptionServerRestartRequired": "Server restart required",
+    "LabelNotificationEnabled": "Enable this notification",
+    "LabelMonitorUsers": "Monitor activity from:",
+    "LabelSendNotificationToUsers": "Send the notification to:",
+    "LabelUseNotificationServices": "Use the following services:",
+    "CategoryUser": "User",
+    "CategorySystem": "System",
+    "CategoryApplication": "Application",
+    "CategoryPlugin": "Plugin",
+    "LabelMessageTitle": "Message title:",
+    "LabelAvailableTokens": "Available tokens:",
+    "AdditionalNotificationServices": "Browse the plugin catalog to install additional notification services.",
+    "OptionAllUsers": "All users",
+    "OptionAdminUsers": "Administrators",
+    "OptionCustomUsers": "Custom",
+    "ButtonArrowUp": "Up",
+    "ButtonArrowDown": "Down",
+    "ButtonArrowLeft": "Left",
+    "ButtonArrowRight": "Right",
+    "ButtonBack": "Back",
+    "ButtonInfo": "Info",
+    "ButtonOsd": "On screen display",
+    "ButtonPageUp": "Page Up",
+    "ButtonPageDown": "Page Down",
+    "PageAbbreviation": "PG",
+    "ButtonHome": "Home",
+    "ButtonSearch": "Search",
+    "ButtonSettings": "Settings",
+    "ButtonTakeScreenshot": "Capture Screenshot",
+    "ButtonLetterUp": "Letter Up",
+    "ButtonLetterDown": "Letter Down",
+    "PageButtonAbbreviation": "PG",
+    "LetterButtonAbbreviation": "A",
+    "TabNowPlaying": "Now Playing",
+    "TabNavigation": "Navigation",
+    "TabControls": "Controls",
+    "ButtonFullscreen": "Toggle fullscreen",
+    "ButtonScenes": "Scenes",
+    "ButtonSubtitles": "Subtitles",
+    "ButtonAudioTracks": "Audio tracks",
+    "ButtonPreviousTrack": "Previous track",
+    "ButtonNextTrack": "Next track",
+    "ButtonStop": "Stop",
+    "ButtonPause": "Pause",
+    "ButtonNext": "Next",
+    "ButtonPrevious": "Previous",
+    "LabelGroupMoviesIntoCollections": "Group movies into collections",
+    "LabelGroupMoviesIntoCollectionsHelp": "When displaying movie lists, movies belonging to a collection will be displayed as one grouped item.",
+    "NotificationOptionPluginError": "Plugin failure",
+    "ButtonVolumeUp": "Volume up",
+    "ButtonVolumeDown": "Volume down",
+    "ButtonMute": "Mute",
+    "HeaderLatestMedia": "Latest Media",
+    "OptionSpecialFeatures": "Special Features",
+    "HeaderCollections": "Collections",
+    "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",
+    "LabelType": "Type:",
+    "LabelPersonRole": "Role:",
+    "LabelPersonRoleHelp": "Role is generally only applicable to actors.",
+    "LabelProfileContainer": "Container:",
+    "LabelProfileVideoCodecs": "Video codecs:",
+    "LabelProfileAudioCodecs": "Audio codecs:",
+    "LabelProfileCodecs": "Codecs:",
+    "HeaderDirectPlayProfile": "Direct Play Profile",
+    "HeaderTranscodingProfile": "Transcoding Profile",
+    "HeaderCodecProfile": "Codec Profile",
+    "HeaderCodecProfileHelp": "Codec profiles indicate the limitations of a device when playing specific codecs. If a limitation applies then the media will be transcoded, even if the codec is configured for direct play.",
+    "HeaderContainerProfile": "Container Profile",
+    "HeaderContainerProfileHelp": "Container profiles indicate the limitations of a device when playing specific formats. If a limitation applies then the media will be transcoded, even if the format is configured for direct play.",
+    "OptionProfileVideo": "Video",
+    "OptionProfileAudio": "Audio",
+    "OptionProfileVideoAudio": "Video Audio",
+    "OptionProfilePhoto": "Photo",
+    "LabelUserLibrary": "User library:",
+    "LabelUserLibraryHelp": "Select which user library to display to the device. Leave empty to inherit the default setting.",
+    "OptionPlainStorageFolders": "Display all folders as plain storage folders",
+    "OptionPlainStorageFoldersHelp": "If enabled, all folders are represented in DIDL as \"object.container.storageFolder\" instead of a more specific type, such as \"object.container.person.musicArtist\".",
+    "OptionPlainVideoItems": "Display all videos as plain video items",
+    "OptionPlainVideoItemsHelp": "If enabled, all videos are represented in DIDL as \"object.item.videoItem\" instead of a more specific type, such as \"object.item.videoItem.movie\".",
+    "LabelSupportedMediaTypes": "Supported Media Types:",
+    "TabIdentification": "Identification",
+    "HeaderIdentification": "Identification",
+    "TabDirectPlay": "Direct Play",
+    "TabContainers": "Containers",
+    "TabCodecs": "Codecs",
+    "TabResponses": "Responses",
+    "HeaderProfileInformation": "Profile Information",
+    "LabelEmbedAlbumArtDidl": "Embed album art in Didl",
+    "LabelEmbedAlbumArtDidlHelp": "Some devices prefer this method for obtaining album art. Others may fail to play with this option enabled.",
+    "LabelAlbumArtPN": "Album art PN:",
+    "LabelAlbumArtHelp": "PN used for album art, within the dlna:profileID attribute on upnp:albumArtURI. Some clients require a specific value, regardless of the size of the image.",
+    "LabelAlbumArtMaxWidth": "Album art max width:",
+    "LabelAlbumArtMaxWidthHelp": "Max resolution of album art exposed via upnp:albumArtURI.",
+    "LabelAlbumArtMaxHeight": "Album art max height:",
+    "LabelAlbumArtMaxHeightHelp": "Max resolution of album art exposed via upnp:albumArtURI.",
+    "LabelIconMaxWidth": "Icon max width:",
+    "LabelIconMaxWidthHelp": "Max resolution of icons exposed via upnp:icon.",
+    "LabelIconMaxHeight": "Icon max height:",
+    "LabelIconMaxHeightHelp": "Max resolution of icons exposed via upnp:icon.",
+    "LabelIdentificationFieldHelp": "A case-insensitive substring or regex expression.",
+    "HeaderProfileServerSettingsHelp": "These values control how Media Browser will present itself to the device.",
+    "LabelMaxBitrate": "Max bitrate:",
+    "LabelMaxBitrateHelp": "Specify a max bitrate in bandwidth constrained environments, or if the device imposes it's own limit.",
+    "LabelMaxStreamingBitrate": "Max streaming bitrate:",
+    "LabelMaxStreamingBitrateHelp": "Specify a max bitrate when streaming.",
+    "LabelMaxStaticBitrate": "Max sync bitrate:",
+    "LabelMaxStaticBitrateHelp": "Specify a max bitrate when syncing content at high quality.",
+    "LabelMusicStaticBitrate": "Music sync bitrate:",
+    "LabelMusicStaticBitrateHelp": "Specify a max bitrate when syncing music",
+    "LabelMusicStreamingTranscodingBitrate": "Music transcoding bitrate:",
+    "LabelMusicStreamingTranscodingBitrateHelp": "Specify a max bitrate when streaming music",
+    "OptionIgnoreTranscodeByteRangeRequests": "Ignore transcode byte range requests",
+    "OptionIgnoreTranscodeByteRangeRequestsHelp": "If enabled, these requests will be honored but will ignore the byte range header.",
+    "LabelFriendlyName": "Friendly name",
+    "LabelManufacturer": "Manufacturer",
+    "LabelManufacturerUrl": "Manufacturer url",
+    "LabelModelName": "Model name",
+    "LabelModelNumber": "Model number",
+    "LabelModelDescription": "Model description",
+    "LabelModelUrl": "Model url",
+    "LabelSerialNumber": "Serial number",
+    "LabelDeviceDescription": "Device description",
+    "HeaderIdentificationCriteriaHelp": "Enter at least one identification criteria.",
+    "HeaderDirectPlayProfileHelp": "Add direct play profiles to indicate which formats the device can handle natively.",
+    "HeaderTranscodingProfileHelp": "Add transcoding profiles to indicate which formats should be used when transcoding is required.",
+    "HeaderResponseProfileHelp": "Response profiles provide a way to customize information sent to the device when playing certain kinds of media.",
+    "LabelXDlnaCap": "X-Dlna cap:",
+    "LabelXDlnaCapHelp": "Determines the content of the X_DLNACAP element in the urn:schemas-dlna-org:device-1-0 namespace.",
+    "LabelXDlnaDoc": "X-Dlna doc:",
+    "LabelXDlnaDocHelp": "Determines the content of the X_DLNADOC element in the urn:schemas-dlna-org:device-1-0 namespace.",
+    "LabelSonyAggregationFlags": "Sony aggregation flags:",
+    "LabelSonyAggregationFlagsHelp": "Determines the content of the aggregationFlags element in the urn:schemas-sonycom:av namespace.",
+    "LabelTranscodingContainer": "Container:",
+    "LabelTranscodingVideoCodec": "Video codec:",
+    "LabelTranscodingVideoProfile": "Video profile:",
+    "LabelTranscodingAudioCodec": "Audio codec:",
+    "OptionEnableM2tsMode": "Enable M2ts mode",
+    "OptionEnableM2tsModeHelp": "Enable m2ts mode when encoding to mpegts.",
+    "OptionEstimateContentLength": "Estimate content length when transcoding",
+    "OptionReportByteRangeSeekingWhenTranscoding": "Report that the server supports byte seeking when transcoding",
+    "OptionReportByteRangeSeekingWhenTranscodingHelp": "This is required for some devices that don't time seek very well.",
+    "HeaderSubtitleDownloadingHelp": "When Media Browser scans your video files it can search for missing subtitles, and download them using a subtitle provider such as OpenSubtitles.org.",
+    "HeaderDownloadSubtitlesFor": "Download subtitles for:",
+    "MessageNoChapterProviders": "Install a chapter provider plugin such as ChapterDb to enable additional chapter options.",
+    "LabelSkipIfGraphicalSubsPresent": "Skip if the video already contains graphical subtitles",
+    "LabelSkipIfGraphicalSubsPresentHelp": "Keeping text versions of subtitles will result in more efficient delivery to mobile clients.",
+    "TabSubtitles": "Subtitles",
+    "TabChapters": "Chapters",
+    "HeaderDownloadChaptersFor": "Download chapter names for:",
+    "LabelOpenSubtitlesUsername": "Open Subtitles username:",
+    "LabelOpenSubtitlesPassword": "Open Subtitles password:",
+    "HeaderChapterDownloadingHelp": "When Media Browser scans your video files it can download friendly chapter names from the internet using chapter plugins such as ChapterDb.",
+    "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language",
+    "LabelSubtitlePlaybackMode": "Subtitle mode:",
+    "LabelDownloadLanguages": "Download languages:",
+    "ButtonRegister": "Register",
+    "LabelSkipIfAudioTrackPresent": "Skip if the default audio track matches the download language",
+    "LabelSkipIfAudioTrackPresentHelp": "Uncheck this to ensure all videos have subtitles, regardless of audio language.",
+    "HeaderSendMessage": "Send Message",
+    "ButtonSend": "Send",
+    "LabelMessageText": "Message text:",
+    "MessageNoAvailablePlugins": "No available plugins.",
+    "LabelDisplayPluginsFor": "Display plugins for:",
+    "PluginTabMediaBrowserClassic": "MB Classic",
+    "PluginTabMediaBrowserTheater": "MB Theater",
+    "LabelEpisodeNamePlain": "Episode name",
+    "LabelSeriesNamePlain": "Series name",
+    "ValueSeriesNamePeriod": "Series.name",
+    "ValueSeriesNameUnderscore": "Series_name",
+    "ValueEpisodeNamePeriod": "Episode.name",
+    "ValueEpisodeNameUnderscore": "Episode_name",
+    "LabelSeasonNumberPlain": "Season number",
+    "LabelEpisodeNumberPlain": "Episode number",
+    "LabelEndingEpisodeNumberPlain": "Ending episode number",
+    "HeaderTypeText": "Enter Text",
+    "LabelTypeText": "Text",
+    "HeaderSearchForSubtitles": "Search for Subtitles",
+    "MessageNoSubtitleSearchResultsFound": "No search results founds.",
+    "TabDisplay": "Display",
+    "TabLanguages": "Languages",
+    "TabWebClient": "Web Client",
+    "LabelEnableThemeSongs": "Enable theme songs",
+    "LabelEnableBackdrops": "Enable backdrops",
+    "LabelEnableThemeSongsHelp": "If enabled, theme songs will be played in the background while browsing the library.",
+    "LabelEnableBackdropsHelp": "If enabled, backdrops will be displayed in the background of some pages while browsing the library.",
+    "HeaderHomePage": "Home Page",
+    "HeaderSettingsForThisDevice": "Settings for This Device",
+    "OptionAuto": "Auto",
+    "OptionYes": "Yes",
+    "OptionNo": "No",
+    "LabelHomePageSection1": "Home page section 1:",
+    "LabelHomePageSection2": "Home page section 2:",
+    "LabelHomePageSection3": "Home page section 3:",
+    "LabelHomePageSection4": "Home page section 4:",
+    "OptionMyViewsButtons": "My views (buttons)",
+    "OptionMyViews": "My views",
+    "OptionMyViewsSmall": "My views (small)",
+    "OptionResumablemedia": "Resume",
+    "OptionLatestMedia": "Latest media",
+    "OptionLatestChannelMedia": "Latest channel items",
+    "HeaderLatestChannelItems": "Latest Channel Items",
+    "OptionNone": "None",
+    "HeaderLiveTv": "Live TV",
+    "HeaderReports": "Reports",
+    "HeaderMetadataManager": "Metadata Manager",
+    "HeaderPreferences": "Preferences",
+    "MessageLoadingChannels": "Loading channel content...",
+    "MessageLoadingContent": "Loading content...",
+    "ButtonMarkRead": "Mark Read",
+    "OptionDefaultSort": "Default",
+    "OptionCommunityMostWatchedSort": "Most Watched",
+    "TabNextUp": "Next Up",
+    "MessageNoMovieSuggestionsAvailable": "No movie suggestions are currently available. Start watching and rating your movies, and then come back to view your recommendations.",
+    "MessageNoCollectionsAvailable": "Collections allow you to enjoy personalized groupings of Movies, Series, Albums, Books and Games. Click the New button to start creating Collections.",
+    "MessageNoPlaylistsAvailable": "Playlists allow you to create lists of content to play consecutively at a time. To add items to playlists, right click or tap and hold, then select Add to Playlist.",
+    "MessageNoPlaylistItemsAvailable": "This playlist is currently empty.",
+    "HeaderWelcomeToMediaBrowserWebClient": "Welcome to the Media Browser Web Client",
+    "ButtonDismiss": "Dismiss",
+    "ButtonTakeTheTour": "Take the tour",
+    "ButtonEditOtherUserPreferences": "Edit this user's personal preferences.",
+    "LabelChannelStreamQuality": "Preferred internet stream quality:",
+    "LabelChannelStreamQualityHelp": "In a low bandwidth environment, limiting quality can help ensure a smooth streaming experience.",
+    "OptionBestAvailableStreamQuality": "Best available",
+    "LabelEnableChannelContentDownloadingFor": "Enable channel content downloading for:",
+    "LabelEnableChannelContentDownloadingForHelp": "Some channels support downloading content prior to viewing. Enable this in low bandwidth enviornments to download channel content during off hours. Content is downloaded as part of the channel download scheduled task.",
+    "LabelChannelDownloadPath": "Channel content download path:",
+    "LabelChannelDownloadPathHelp": "Specify a custom download path if desired. Leave empty to download to an internal program data folder.",
+    "LabelChannelDownloadAge": "Delete content after: (days)",
+    "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.",
+    "LabelSelectCollection": "Select collection:",
+    "ButtonOptions": "Options",
+    "ViewTypeMovies": "Movies",
+    "ViewTypeTvShows": "TV",
+    "ViewTypeGames": "Games",
+    "ViewTypeMusic": "Music",
+    "ViewTypeBoxSets": "Collections",
+    "ViewTypeChannels": "Channels",
+    "ViewTypeLiveTV": "Live TV",
+    "ViewTypeLiveTvNowPlaying": "Now Airing",
+    "ViewTypeLatestGames": "Latest Games",
+    "ViewTypeRecentlyPlayedGames": "Recently Played",
+    "ViewTypeGameFavorites": "Favorites",
+    "ViewTypeGameSystems": "Game Systems",
+    "ViewTypeGameGenres": "Genres",
+    "ViewTypeTvResume": "Resume",
+    "ViewTypeTvNextUp": "Next Up",
+    "ViewTypeTvLatest": "Latest",
+    "ViewTypeTvShowSeries": "Series",
+    "ViewTypeTvGenres": "Genres",
+    "ViewTypeTvFavoriteSeries": "Favorite Series",
+    "ViewTypeTvFavoriteEpisodes": "Favorite Episodes",
+    "ViewTypeMovieResume": "Resume",
+    "ViewTypeMovieLatest": "Latest",
+    "ViewTypeMovieMovies": "Movies",
+    "ViewTypeMovieCollections": "Collections",
+    "ViewTypeMovieFavorites": "Favorites",
+    "ViewTypeMovieGenres": "Genres",
+    "ViewTypeMusicLatest": "Latest",
+    "ViewTypeMusicAlbums": "Albums",
+    "ViewTypeMusicAlbumArtists": "Album Artists",
+    "HeaderOtherDisplaySettings": "Display Settings",
+    "ViewTypeMusicSongs": "Songs",
+    "ViewTypeMusicFavorites": "Favorites",
+    "ViewTypeMusicFavoriteAlbums": "Favorite Albums",
+    "ViewTypeMusicFavoriteArtists": "Favorite Artists",
+    "ViewTypeMusicFavoriteSongs": "Favorite Songs",
+    "HeaderMyViews": "My Views",
+    "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:",
+    "LabelSelectFolderGroupsHelp": "Folders that are unchecked will be displayed by themselves in their own view.",
+    "OptionDisplayAdultContent": "Display adult content",
+    "OptionLibraryFolders": "Media folders",
+    "TitleRemoteControl": "Remote Control",
+    "OptionLatestTvRecordings": "Latest recordings",
+    "LabelProtocolInfo": "Protocol info:",
+    "LabelProtocolInfoHelp": "The value that will be used when responding to GetProtocolInfo requests from the device.",
+    "TabKodiMetadata": "Kodi",
+    "HeaderKodiMetadataHelp": "Media Browser includes native support for Kodi Nfo metadata and images. To enable or disable Kodi metadata, use the Advanced tab to configure options for your media types.",
+    "LabelKodiMetadataUser": "Add user watch data to nfo's for:",
+    "LabelKodiMetadataUserHelp": "Enable this to keep watch data in sync between Media Browser and Kodi.",
+    "LabelKodiMetadataDateFormat": "Release date format:",
+    "LabelKodiMetadataDateFormatHelp": "All dates within nfo's will be read and written to using this format.",
+    "LabelKodiMetadataSaveImagePaths": "Save image paths within nfo files",
+    "LabelKodiMetadataSaveImagePathsHelp": "This is recommended if you have image file names that don't conform to Kodi guidelines.",
+    "LabelKodiMetadataEnablePathSubstitution": "Enable path substitution",
+    "LabelKodiMetadataEnablePathSubstitutionHelp": "Enables path substitution of image paths using the server's path substitution settings.",
+    "LabelKodiMetadataEnablePathSubstitutionHelp2": "See path substitution.",
+    "LabelGroupChannelsIntoViews": "Display the following channels directly within my views:",
+    "LabelGroupChannelsIntoViewsHelp": "If enabled, these channels will be displayed directly alongside other views. If disabled, they'll be displayed within a separate Channels view.",
+    "LabelDisplayCollectionsView": "Display a collections view to show movie collections",
+    "LabelKodiMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs",
+    "LabelKodiMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Kodi skin compatibility.",
+    "TabServices": "Services",
+    "TabLogs": "Logs",
+    "HeaderServerLogFiles": "Server log files:",
+    "TabBranding": "Branding",
+    "HeaderBrandingHelp": "Customize the appearance of Media Browser to fit the needs of your group or organization.",
+    "LabelLoginDisclaimer": "Login disclaimer:",
+    "LabelLoginDisclaimerHelp": "This will be displayed at the bottom of the login page.",
+    "LabelAutomaticallyDonate": "Automatically donate this amount every month",
+    "LabelAutomaticallyDonateHelp": "You can cancel at any time via your PayPal account.",
+    "OptionList": "List",
+    "TabDashboard": "Dashboard",
+    "TitleServer": "Server",
+    "LabelCache": "Cache:",
+    "LabelLogs": "Logs:",
+    "LabelMetadata": "Metadata:",
+    "LabelImagesByName": "Images by name:",
+    "LabelTranscodingTemporaryFiles": "Transcoding temporary files:",
+    "HeaderLatestMusic": "Latest Music",
+    "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.",
+    "HeaderApiKey": "Api Key",
+    "HeaderApp": "App",
+    "HeaderDevice": "Device",
+    "HeaderUser": "User",
+    "HeaderDateIssued": "Date Issued",
+    "LabelChapterName": "Chapter {0}",
+    "HeaderNewApiKey": "New Api Key",
+    "LabelAppName": "App name",
+    "LabelAppNameExample": "Example: Sickbeard, NzbDrone",
+    "HeaderNewApiKeyHelp": "Grant an application permission to communicate with Media Browser.",
+    "HeaderHttpHeaders": "Http Headers",
+    "HeaderIdentificationHeader": "Identification Header",
+    "LabelValue": "Value:",
+    "LabelMatchType": "Match type:",
+    "OptionEquals": "Equals",
+    "OptionRegex": "Regex",
+    "OptionSubstring": "Substring",
+    "TabView": "View",
+    "TabSort": "Sort",
+    "TabFilter": "Filter",
+    "ButtonView": "View",
+    "LabelPageSize": "Item limit:",
+    "LabelPath": "Path:",
+    "LabelView": "View:",
+    "TabUsers": "Users",
+    "LabelSortName": "Sort name:",
+    "LabelDateAdded": "Date added:",
+    "HeaderFeatures": "Features",
+    "HeaderAdvanced": "Advanced",
+    "ButtonSync": "Sync",
+    "TabScheduledTasks": "Scheduled Tasks",
+    "HeaderChapters": "Chapters",
+    "HeaderResumeSettings": "Resume Settings",
+    "TabSync": "Sync",
+    "TitleUsers": "Users",
+    "LabelProtocol": "Protocol:",
+    "OptionProtocolHttp": "Http",
+    "OptionProtocolHls": "Http Live Streaming",
+    "LabelContext": "Context:",
+    "OptionContextStreaming": "Streaming",
+    "OptionContextStatic": "Sync",
+    "ButtonAddToPlaylist": "Add to playlist",
+    "TabPlaylists": "Playlists",
+    "ButtonClose": "Close",
+    "LabelAllLanguages": "All languages",
+    "HeaderBrowseOnlineImages": "Browse Online Images",
+    "LabelSource": "Source:",
+    "OptionAll": "All",
+    "LabelImage": "Image:",
+    "ButtonBrowseImages": "Browse Images",
+    "HeaderImages": "Images",
+    "HeaderBackdrops": "Backdrops",
+    "HeaderScreenshots": "Screenshots",
+    "HeaderAddUpdateImage": "Add\/Update Image",
+    "LabelJpgPngOnly": "JPG\/PNG only",
+    "LabelImageType": "Image type:",
+    "OptionPrimary": "Primary",
+    "OptionArt": "Art",
+    "OptionBox": "Box",
+    "OptionBoxRear": "Box rear",
+    "OptionDisc": "Disc",
+    "OptionLogo": "Logo",
+    "OptionMenu": "Menu",
+    "OptionScreenshot": "Screenshot",
+    "OptionLocked": "Locked",
+    "OptionUnidentified": "Unidentified",
+    "OptionMissingParentalRating": "Missing parental rating",
+    "OptionStub": "Stub",
+    "HeaderEpisodes": "Episodes:",
+    "OptionSeason0": "Season 0",
+    "LabelReport": "Report:",
+    "OptionReportSongs": "Songs",
+    "OptionReportSeries": "Series",
+    "OptionReportSeasons": "Seasons",
+    "OptionReportTrailers": "Trailers",
+    "OptionReportMusicVideos": "Music videos",
+    "OptionReportMovies": "Movies",
+    "OptionReportHomeVideos": "Home videos",
+    "OptionReportGames": "Games",
+    "OptionReportEpisodes": "Episodes",
+    "OptionReportCollections": "Collections",
+    "OptionReportBooks": "Books",
+    "OptionReportArtists": "Artists",
+    "OptionReportAlbums": "Albums"
+}

+ 4 - 8
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -240,7 +240,8 @@
     <Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
     <Compile Include="Persistence\SqliteShrinkMemoryTimer.cs" />
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
     <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
-    <Compile Include="Playlists\PlaylistImageEnhancer.cs" />
+    <Compile Include="Photos\PhotoAlbumImageProvider.cs" />
+    <Compile Include="Playlists\PlaylistImageProvider.cs" />
     <Compile Include="Playlists\PlaylistManager.cs" />
     <Compile Include="Playlists\PlaylistManager.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
     <Compile Include="ScheduledTasks\PeopleValidationTask.cs" />
@@ -400,6 +401,8 @@
     <EmbeddedResource Include="Localization\Server\tr.json" />
     <EmbeddedResource Include="Localization\Server\tr.json" />
     <EmbeddedResource Include="Localization\JavaScript\hr.json" />
     <EmbeddedResource Include="Localization\JavaScript\hr.json" />
     <EmbeddedResource Include="Localization\Server\hr.json" />
     <EmbeddedResource Include="Localization\Server\hr.json" />
+    <EmbeddedResource Include="Localization\JavaScript\zh_CN.json" />
+    <EmbeddedResource Include="Localization\Server\zh_CN.json" />
     <None Include="packages.config" />
     <None Include="packages.config" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
@@ -511,13 +514,6 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup />
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 113 - 68
MediaBrowser.Server.Implementations/Playlists/PlaylistImageEnhancer.cs → MediaBrowser.Server.Implementations/Photos/PhotoAlbumImageProvider.cs

@@ -1,44 +1,115 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.Playlists;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Drawing;
-using MediaBrowser.Model.Entities;
-using MoreLinq;
-using System;
+using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Drawing;
 using System.Drawing;
 using System.Drawing.Drawing2D;
 using System.Drawing.Drawing2D;
 using System.Drawing.Imaging;
 using System.Drawing.Imaging;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
+using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Common.Extensions;
+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.Playlists;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MoreLinq;
 
 
-namespace MediaBrowser.Server.Implementations.Playlists
+namespace MediaBrowser.Server.Implementations.Photos
 {
 {
-    public class PlaylistImageEnhancer : IImageEnhancer
+    public class PhotoAlbumImageProvider : ICustomMetadataProvider<PhotoAlbum>, IHasChangeMonitor
     {
     {
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
+        private readonly IProviderManager _provider;
 
 
-        public PlaylistImageEnhancer(IFileSystem fileSystem)
+        public PhotoAlbumImageProvider(IFileSystem fileSystem, IProviderManager provider)
         {
         {
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
+            _provider = provider;
         }
         }
 
 
-        public bool Supports(IHasImages item, ImageType imageType)
+        public async Task<ItemUpdateType> FetchAsync(PhotoAlbum item, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
         {
-            return (imageType == ImageType.Primary || imageType == ImageType.Thumb) && item is Playlist;
+            var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false);
+            var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false);
+
+            return primaryResult | thumbResult;
         }
         }
 
 
-        public MetadataProviderPriority Priority
+        private Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            var items = GetItemsWithImages(item);
+            var cacheKey = GetConfigurationCacheKey(items);
+
+            if (!HasChanged(item, imageType, cacheKey))
+            {
+                return Task.FromResult(ItemUpdateType.None);
+            }
+
+            return FetchAsyncInternal(item, imageType, cacheKey, options, cancellationToken);
+        }
+
+        private async Task<ItemUpdateType> FetchAsyncInternal(IHasImages item, ImageType imageType, string cacheKey, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            var img = await CreateImageAsync(item, imageType, 0).ConfigureAwait(false);
+
+            if (img == null)
+            {
+                return ItemUpdateType.None;
+            }
+
+            using (var ms = new MemoryStream())
+            {
+                img.Save(ms, ImageFormat.Png);
+
+                ms.Position = 0;
+
+                await _provider.SaveImage(item, ms, "image/png", imageType, null, cacheKey, cancellationToken).ConfigureAwait(false);
+            }
+
+            return ItemUpdateType.ImageUpdate;
+        }
+
+        private bool HasChanged(IHasImages item, ImageType type, string cacheKey)
+        {
+            var image = item.GetImageInfo(type, 0);
+
+            if (image != null)
+            {
+                if (!_fileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
+                {
+                    return false;
+                }
+
+                var currentPathCacheKey = (Path.GetFileNameWithoutExtension(image.Path) ?? string.Empty).Split('_').LastOrDefault();
+
+                if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private const string Version = "3";
+
+        public string GetConfigurationCacheKey(List<BaseItem> items)
         {
         {
-            get { return MetadataProviderPriority.First; }
+            return (Version + "_" + string.Join(",", items.Select(i => i.Id.ToString("N")).ToArray())).GetMD5().ToString("N");
         }
         }
 
 
         private List<BaseItem> GetItemsWithImages(IHasImages item)
         private List<BaseItem> GetItemsWithImages(IHasImages item)
         {
         {
+            var photoAlbum = item as PhotoAlbum;
+            if (photoAlbum != null)
+            {
+                return GetFinalItems(photoAlbum.RecursiveChildren.Where(i => i is Photo).ToList());
+            }
+
             var playlist = (Playlist)item;
             var playlist = (Playlist)item;
 
 
             var items = playlist.GetManageableItems()
             var items = playlist.GetManageableItems()
@@ -78,6 +149,11 @@ namespace MediaBrowser.Server.Implementations.Playlists
                 .DistinctBy(i => i.Id)
                 .DistinctBy(i => i.Id)
                 .ToList();
                 .ToList();
 
 
+            return GetFinalItems(items);
+        }
+
+        private List<BaseItem> GetFinalItems(List<BaseItem> items)
+        {
             // Rotate the images no more than once per day
             // Rotate the images no more than once per day
             var random = new Random(DateTime.Now.DayOfYear).Next();
             var random = new Random(DateTime.Now.DayOfYear).Next();
 
 
@@ -88,66 +164,18 @@ namespace MediaBrowser.Server.Implementations.Playlists
                 .ToList();
                 .ToList();
         }
         }
 
 
-        private const string Version = "3";
-
-        public string GetConfigurationCacheKey(List<BaseItem> items)
-        {
-            return Version + "_" + string.Join(",", items.Select(i => i.Id.ToString("N")).ToArray());
-        }
-
-        public string GetConfigurationCacheKey(IHasImages item, ImageType imageType)
-        {
-            var items = GetItemsWithImages(item);
-
-            return GetConfigurationCacheKey(items);
-        }
-
-        private const int SquareImageSize = 800;
-        private const int ThumbImageWidth = 1600;
-        private const int ThumbImageHeight = 900;
-
-        public ImageSize GetEnhancedImageSize(IHasImages item, ImageType imageType, int imageIndex, ImageSize originalImageSize)
-        {
-            var items = GetItemsWithImages(item);
-
-            if (items.Count == 0)
-            {
-                return originalImageSize;
-            }
-
-            if (imageType == ImageType.Thumb)
-            {
-                return new ImageSize
-                {
-                    Height = ThumbImageHeight,
-                    Width = ThumbImageWidth
-                };
-            }
-
-            return new ImageSize
-            {
-                Height = SquareImageSize,
-                Width = SquareImageSize
-            };
-        }
-
-        public async Task<Image> EnhanceImageAsync(IHasImages item, Image originalImage, ImageType imageType, int imageIndex)
+        public async Task<Image> CreateImageAsync(IHasImages item, ImageType imageType, int imageIndex)
         {
         {
             var items = GetItemsWithImages(item);
             var items = GetItemsWithImages(item);
 
 
             if (items.Count == 0)
             if (items.Count == 0)
             {
             {
-                return originalImage;
+                return null;
             }
             }
 
 
-            var img = imageType == ImageType.Thumb  ?
+            return imageType == ImageType.Thumb ?
                 await GetThumbCollage(items).ConfigureAwait(false) :
                 await GetThumbCollage(items).ConfigureAwait(false) :
                 await GetSquareCollage(items).ConfigureAwait(false);
                 await GetSquareCollage(items).ConfigureAwait(false);
-
-            using (originalImage)
-            {
-                return img;
-            }
         }
         }
 
 
         private Task<Image> GetThumbCollage(List<BaseItem> items)
         private Task<Image> GetThumbCollage(List<BaseItem> items)
@@ -217,6 +245,10 @@ namespace MediaBrowser.Server.Implementations.Playlists
             return img;
             return img;
         }
         }
 
 
+        private const int SquareImageSize = 800;
+        private const int ThumbImageWidth = 1600;
+        private const int ThumbImageHeight = 900;
+
         private async Task<Image> GetSquareCollage(List<string> files)
         private async Task<Image> GetSquareCollage(List<string> files)
         {
         {
             if (files.Count < 4)
             if (files.Count < 4)
@@ -288,5 +320,18 @@ namespace MediaBrowser.Server.Implementations.Playlists
                 return Image.FromStream(memoryStream, true, false);
                 return Image.FromStream(memoryStream, true, false);
             }
             }
         }
         }
+
+        public string Name
+        {
+            get { return "Dynamic Image Provider"; }
+        }
+
+        public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+        {
+            var items = GetItemsWithImages(item);
+            var cacheKey = GetConfigurationCacheKey(items);
+
+            return HasChanged(item, ImageType.Primary, cacheKey) || HasChanged(item, ImageType.Thumb, cacheKey);
+        }
     }
     }
 }
 }

+ 345 - 0
MediaBrowser.Server.Implementations/Playlists/PlaylistImageProvider.cs

@@ -0,0 +1,345 @@
+using MediaBrowser.Common.Extensions;
+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.Playlists;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MoreLinq;
+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;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Playlists
+{
+    public class PlaylistImageProvider : ICustomMetadataProvider<Playlist>, IHasChangeMonitor
+    {
+        private readonly IFileSystem _fileSystem;
+        private readonly IProviderManager _provider;
+
+        public PlaylistImageProvider(IFileSystem fileSystem, IProviderManager provider)
+        {
+            _fileSystem = fileSystem;
+            _provider = provider;
+        }
+
+        public async Task<ItemUpdateType> FetchAsync(Playlist item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false);
+            var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false);
+
+            return primaryResult | thumbResult;
+        }
+
+        public async Task<ItemUpdateType> FetchAsync(PhotoAlbum item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false);
+            var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false);
+
+            return primaryResult | thumbResult;
+        }
+
+        private Task<ItemUpdateType> FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            var items = GetItemsWithImages(item);
+            var cacheKey = GetConfigurationCacheKey(items);
+
+            if (!HasChanged(item, imageType, cacheKey))
+            {
+                return Task.FromResult(ItemUpdateType.None);
+            }
+
+            return FetchAsyncInternal(item, imageType, cacheKey, options, cancellationToken);
+        }
+
+        private async Task<ItemUpdateType> FetchAsyncInternal(IHasImages item, ImageType imageType, string cacheKey, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            var img = await CreateImageAsync(item, imageType, 0).ConfigureAwait(false);
+
+            if (img == null)
+            {
+                return ItemUpdateType.None;
+            }
+
+            using (var ms = new MemoryStream())
+            {
+                img.Save(ms, ImageFormat.Png);
+
+                ms.Position = 0;
+
+                await _provider.SaveImage(item, ms, "image/png", imageType, null, cacheKey, cancellationToken).ConfigureAwait(false);
+            }
+
+            return ItemUpdateType.ImageUpdate;
+        }
+
+        private bool HasChanged(IHasImages item, ImageType type, string cacheKey)
+        {
+            var image = item.GetImageInfo(type, 0);
+
+            if (image != null)
+            {
+                if (!_fileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
+                {
+                    return false;
+                }
+
+                var currentPathCacheKey = (Path.GetFileNameWithoutExtension(image.Path) ?? string.Empty).Split('_').LastOrDefault();
+
+                if (string.Equals(cacheKey, currentPathCacheKey, StringComparison.OrdinalIgnoreCase))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private const string Version = "3";
+
+        public string GetConfigurationCacheKey(List<BaseItem> items)
+        {
+            return (Version + "_" + string.Join(",", items.Select(i => i.Id.ToString("N")).ToArray())).GetMD5().ToString("N");
+        }
+
+        private List<BaseItem> GetItemsWithImages(IHasImages item)
+        {
+            var photoAlbum = item as PhotoAlbum;
+            if (photoAlbum != null)
+            {
+                return GetFinalItems(photoAlbum.RecursiveChildren.Where(i => i is Photo).ToList());
+            }
+
+            var playlist = (Playlist)item;
+
+            var items = playlist.GetManageableItems()
+                .Select(i =>
+                {
+                    var subItem = i.Item2;
+
+                    var episode = subItem as Episode;
+
+                    if (episode != null)
+                    {
+                        var series = episode.Series;
+                        if (series != null && series.HasImage(ImageType.Primary))
+                        {
+                            return series;
+                        }
+                    }
+
+                    if (subItem.HasImage(ImageType.Primary))
+                    {
+                        return subItem;
+                    }
+
+                    var parent = subItem.Parent;
+
+                    if (parent != null && parent.HasImage(ImageType.Primary))
+                    {
+                        if (parent is MusicAlbum)
+                        {
+                            return parent;
+                        }
+                    }
+
+                    return null;
+                })
+                .Where(i => i != null)
+                .DistinctBy(i => i.Id)
+                .ToList();
+
+            return GetFinalItems(items);
+        }
+
+        private List<BaseItem> GetFinalItems(List<BaseItem> items)
+        {
+            // Rotate the images no more than once per day
+            var random = new Random(DateTime.Now.DayOfYear).Next();
+
+            return items
+                .OrderBy(i => random - items.IndexOf(i))
+                .Take(4)
+                .OrderBy(i => i.Name)
+                .ToList();
+        }
+
+        public async Task<Image> CreateImageAsync(IHasImages item, ImageType imageType, int imageIndex)
+        {
+            var items = GetItemsWithImages(item);
+
+            if (items.Count == 0)
+            {
+                return null;
+            }
+
+            return imageType == ImageType.Thumb ?
+                await GetThumbCollage(items).ConfigureAwait(false) :
+                await GetSquareCollage(items).ConfigureAwait(false);
+        }
+
+        private Task<Image> GetThumbCollage(List<BaseItem> items)
+        {
+            return GetThumbCollage(items.Select(i => i.GetImagePath(ImageType.Primary)).ToList());
+        }
+
+        private Task<Image> GetSquareCollage(List<BaseItem> items)
+        {
+            return GetSquareCollage(items.Select(i => i.GetImagePath(ImageType.Primary)).ToList());
+        }
+
+        private async Task<Image> GetThumbCollage(List<string> files)
+        {
+            if (files.Count < 3)
+            {
+                return await GetSingleImage(files).ConfigureAwait(false);
+            }
+
+            const int rows = 1;
+            const int cols = 3;
+
+            const int cellWidth = 2 * (ThumbImageWidth / 3);
+            const int cellHeight = ThumbImageHeight;
+            var index = 0;
+
+            var img = new Bitmap(ThumbImageWidth, ThumbImageHeight, PixelFormat.Format32bppPArgb);
+
+            using (var graphics = Graphics.FromImage(img))
+            {
+                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++)
+                    {
+                        var x = col * (cellWidth / 2);
+                        var y = row * cellHeight;
+
+                        if (files.Count > index)
+                        {
+                            using (var fileStream = _fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+                            {
+                                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);
+                                    }
+                                }
+                            }
+                        }
+
+                        index++;
+                    }
+                }
+            }
+
+            return img;
+        }
+
+        private const int SquareImageSize = 800;
+        private const int ThumbImageWidth = 1600;
+        private const int ThumbImageHeight = 900;
+        
+        private async Task<Image> GetSquareCollage(List<string> files)
+        {
+            if (files.Count < 4)
+            {
+                return await GetSingleImage(files).ConfigureAwait(false);
+            }
+
+            const int rows = 2;
+            const int cols = 2;
+
+            const int singleSize = SquareImageSize / 2;
+            var index = 0;
+
+            var img = new Bitmap(SquareImageSize, SquareImageSize, PixelFormat.Format32bppPArgb);
+
+            using (var graphics = Graphics.FromImage(img))
+            {
+                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++)
+                    {
+                        var x = col * singleSize;
+                        var y = row * singleSize;
+
+                        using (var fileStream = _fileSystem.GetFileStream(files[index], FileMode.Open, FileAccess.Read, FileShare.Read, true))
+                        {
+                            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);
+                                }
+                            }
+                        }
+
+                        index++;
+                    }
+                }
+            }
+
+            return img;
+        }
+
+        private Task<Image> GetSingleImage(List<string> files)
+        {
+            return GetImage(files[0]);
+        }
+
+        private async Task<Image> GetImage(string file)
+        {
+            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);
+            }
+        }
+
+        public string Name
+        {
+            get { return "Dynamic Image Provider"; }
+        }
+
+        public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
+        {
+            var items = GetItemsWithImages(item);
+            var cacheKey = GetConfigurationCacheKey(items);
+
+            return HasChanged(item, ImageType.Primary, cacheKey) || HasChanged(item, ImageType.Thumb, cacheKey);
+        }
+    }
+}

+ 0 - 7
MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj

@@ -189,11 +189,4 @@
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
   </ItemGroup>
   </ItemGroup>
-  <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>
 </Project>

+ 0 - 7
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -266,11 +266,4 @@ del "$(SolutionDir)..\Deploy\MBServer.zip"
     </GetAssemblyIdentity>
     </GetAssemblyIdentity>
     <Exec Command="copy &quot;$(SolutionDir)..\Deploy\MBServer.zip&quot;  &quot;$(SolutionDir)..\Deploy\MBServer_%(CurrentAssembly.Version).zip&quot; /y" Condition="'$(ConfigurationName)' == 'Release'" />
     <Exec Command="copy &quot;$(SolutionDir)..\Deploy\MBServer.zip&quot;  &quot;$(SolutionDir)..\Deploy\MBServer_%(CurrentAssembly.Version).zip&quot; /y" Condition="'$(ConfigurationName)' == 'Release'" />
   </Target>
   </Target>
-  <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>
 </Project>

+ 0 - 7
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -2264,13 +2264,6 @@
     <PostBuildEvent>
     <PostBuildEvent>
     </PostBuildEvent>
     </PostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
-  <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>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   <!-- 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.
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">
   <Target Name="BeforeBuild">

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.494</version>
+        <version>3.0.496</version>
         <title>MediaBrowser.Common.Internal</title>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <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>
         <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>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.494" />
+            <dependency id="MediaBrowser.Common" version="3.0.496" />
             <dependency id="NLog" version="3.1.0.0" />
             <dependency id="NLog" version="3.1.0.0" />
             <dependency id="SimpleInjector" version="2.6.0" />
             <dependency id="SimpleInjector" version="2.6.0" />
             <dependency id="sharpcompress" version="0.10.2" />
             <dependency id="sharpcompress" version="0.10.2" />

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common</id>
         <id>MediaBrowser.Common</id>
-        <version>3.0.494</version>
+        <version>3.0.496</version>
         <title>MediaBrowser.Common</title>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>

+ 1 - 1
Nuget/MediaBrowser.Model.Signed.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Model.Signed</id>
         <id>MediaBrowser.Model.Signed</id>
-        <version>3.0.494</version>
+        <version>3.0.496</version>
         <title>MediaBrowser.Model - Signed Edition</title>
         <title>MediaBrowser.Model - Signed Edition</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Server.Core</id>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.494</version>
+        <version>3.0.496</version>
         <title>Media Browser.Server.Core</title>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.494" />
+            <dependency id="MediaBrowser.Common" version="3.0.496" />
         </dependencies>
         </dependencies>
     </metadata>
     </metadata>
     <files>
     <files>