aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/AppThemeService.cs2
-rw-r--r--MediaBrowser.Api/BaseApiService.cs18
-rw-r--r--MediaBrowser.Api/Images/ImageService.cs25
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs16
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs17
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs61
-rw-r--r--MediaBrowser.Api/PluginService.cs8
-rw-r--r--MediaBrowser.Api/System/SystemService.cs21
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj4
-rw-r--r--MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs61
-rw-r--r--MediaBrowser.Common.Implementations/Security/MBRegistration.cs99
-rw-r--r--MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs154
-rw-r--r--MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs14
-rw-r--r--MediaBrowser.Common/Security/ISecurityManager.cs16
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs17
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs1
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs1
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs2
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/Net/AuthenticatedAttribute.cs8
-rw-r--r--MediaBrowser.Controller/Net/IAuthService.cs2
-rw-r--r--MediaBrowser.Controller/Net/IHttpResultFactory.cs42
-rw-r--r--MediaBrowser.Controller/Net/StaticResultOptions.cs42
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs11
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs36
-rw-r--r--MediaBrowser.Dlna/Ssdp/SsdpHandler.cs5
-rw-r--r--MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj1
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/AssParser.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs13
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs4
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs7
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs68
-rw-r--r--MediaBrowser.Model/Dto/BaseItemDto.cs6
-rw-r--r--MediaBrowser.Model/Entities/MBRegistrationRecord.cs32
-rw-r--r--MediaBrowser.Model/Entities/PluginSecurityInfo.cs6
-rw-r--r--MediaBrowser.Providers/Photos/PhotoProvider.cs15
-rw-r--r--MediaBrowser.Server.Implementations/Dto/DtoService.cs16
-rw-r--r--MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs16
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs14
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs139
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs2
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs23
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs3
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs42
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs13
-rw-r--r--MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs5
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/da.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/de.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/el.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/es.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/he.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/it.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json117
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json29
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json15
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json15
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json11
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ar.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ca.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/da.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/de.json20
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/el.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/en_GB.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/en_US.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/es.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/es_MX.json24
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/fr.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/he.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/it.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/kk.json50
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ko.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ms.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/nb.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/nl.json42
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pl.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json28
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/ru.json46
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/server.json12
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/sv.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/tr.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/vi.json10
-rw-r--r--MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json10
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs14
-rw-r--r--MediaBrowser.Tests/MediaBrowser.Tests.csproj4
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs (renamed from MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs)13
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs22
-rw-r--r--MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ass (renamed from MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ssa)0
108 files changed, 1322 insertions, 685 deletions
diff --git a/MediaBrowser.Api/AppThemeService.cs b/MediaBrowser.Api/AppThemeService.cs
index 0c8a0aaa6..87084e415 100644
--- a/MediaBrowser.Api/AppThemeService.cs
+++ b/MediaBrowser.Api/AppThemeService.cs
@@ -94,7 +94,7 @@ namespace MediaBrowser.Api
var contentType = MimeTypes.GetMimeType(info.Path);
- return ToCachedResult(cacheGuid, info.DateModified, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
+ return ResultFactory.GetCachedResult(Request, cacheGuid, null, cacheDuration, () => _fileSystem.GetFileStream(info.Path, FileMode.Open, FileAccess.Read, FileShare.Read), contentType);
}
}
}
diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs
index 727ee6fbc..1af7054d9 100644
--- a/MediaBrowser.Api/BaseApiService.cs
+++ b/MediaBrowser.Api/BaseApiService.cs
@@ -98,24 +98,6 @@ namespace MediaBrowser.Api
}
/// <summary>
- /// To the cached result.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="cacheKey">The cache key.</param>
- /// <param name="lastDateModified">The last date modified.</param>
- /// <param name="cacheDuration">Duration of the cache.</param>
- /// <param name="factoryFn">The factory fn.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <returns>System.Object.</returns>
- /// <exception cref="System.ArgumentNullException">cacheKey</exception>
- protected object ToCachedResult<T>(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, string contentType, IDictionary<string,string> responseHeaders = null)
- where T : class
- {
- return ResultFactory.GetCachedResult(Request, cacheKey, lastDateModified, cacheDuration, factoryFn, contentType, responseHeaders);
- }
-
- /// <summary>
/// To the static file result.
/// </summary>
/// <param name="path">The path.</param>
diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs
index 43e9ad3ef..2213a5af1 100644
--- a/MediaBrowser.Api/Images/ImageService.cs
+++ b/MediaBrowser.Api/Images/ImageService.cs
@@ -361,7 +361,7 @@ namespace MediaBrowser.Api.Images
/// <returns>System.Object.</returns>
public object Get(GetItemImage request)
{
- var item = string.IsNullOrEmpty(request.Id) ?
+ var item = string.IsNullOrEmpty(request.Id) ?
_libraryManager.RootFolder :
_libraryManager.GetItemById(request.Id);
@@ -542,24 +542,24 @@ namespace MediaBrowser.Api.Images
{"realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*"}
};
- return GetImageResult(item,
- request,
- imageInfo,
- supportedImageEnhancers,
- contentType,
+ return GetImageResult(item,
+ request,
+ imageInfo,
+ supportedImageEnhancers,
+ contentType,
cacheDuration,
responseHeaders,
isHeadRequest)
.Result;
}
- private async Task<object> GetImageResult(IHasImages item,
+ private async Task<object> GetImageResult(IHasImages item,
ImageRequest request,
ItemImageInfo image,
List<IImageEnhancer> enhancers,
string contentType,
TimeSpan? cacheDuration,
- IDictionary<string,string> headers,
+ IDictionary<string, string> headers,
bool isHeadRequest)
{
var cropwhitespace = request.Type == ImageType.Logo || request.Type == ImageType.Art;
@@ -590,7 +590,14 @@ namespace MediaBrowser.Api.Images
var file = await _imageProcessor.ProcessImage(options).ConfigureAwait(false);
- return ResultFactory.GetStaticFileResult(Request, file, contentType, cacheDuration, FileShare.Read, headers, isHeadRequest);
+ return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ {
+ CacheDuration = cacheDuration,
+ ResponseHeaders = headers,
+ ContentType = contentType,
+ IsHeadRequest = isHeadRequest,
+ Path = file
+ });
}
private string GetMimeType(ImageOutputFormat format, string path)
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index a0a8ee61e..31a81de73 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -348,14 +348,16 @@ namespace MediaBrowser.Api.Playback
var profileScore = 0;
string crf;
+ var qmin = "0";
+ var qmax = "50";
switch (qualitySetting)
{
case EncodingQuality.HighSpeed:
- crf = "12";
+ crf = "10";
break;
case EncodingQuality.HighQuality:
- crf = "8";
+ crf = "6";
break;
case EncodingQuality.MaxQuality:
crf = "4";
@@ -371,11 +373,13 @@ namespace MediaBrowser.Api.Playback
// Max of 2
profileScore = Math.Min(profileScore, 2);
-
+
// http://www.webmproject.org/docs/encoder-parameters/
- param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1}",
+ param = string.Format("-speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
profileScore.ToString(UsCulture),
- crf);
+ crf,
+ qmin,
+ qmax);
}
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase))
@@ -789,7 +793,7 @@ namespace MediaBrowser.Api.Playback
{
if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
{
- var url = "http://localhost:8096/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
+ var url = "http://localhost:" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(UsCulture) + "/mediabrowser/videos/" + state.Request.Id + "/stream?static=true&Throttle=true&mediaSourceId=" + state.Request.MediaSourceId;
return string.Format("\"{0}\"", url);
}
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index 0d90e3739..346af016e 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -10,7 +10,6 @@ using ServiceStack;
using System;
using System.IO;
using System.Linq;
-using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback.Hls
@@ -63,6 +62,14 @@ namespace MediaBrowser.Api.Playback.Hls
{
}
+ protected override bool SupportsThrottling
+ {
+ get
+ {
+ return false;
+ }
+ }
+
/// <summary>
/// Gets the specified request.
/// </summary>
@@ -79,14 +86,6 @@ namespace MediaBrowser.Api.Playback.Hls
return ResultFactory.GetStaticFileResult(Request, file);
}
- protected override bool SupportsThrottling
- {
- get
- {
- return false;
- }
- }
-
/// <summary>
/// Called when [begin request].
/// </summary>
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index d8255bd29..997cc7ca4 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
+using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using ServiceStack.Web;
@@ -26,7 +27,8 @@ namespace MediaBrowser.Api.Playback.Progressive
protected readonly IImageProcessor ImageProcessor;
protected readonly IHttpClient HttpClient;
- protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
+ protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, IChannelManager channelManager, ISubtitleEncoder subtitleEncoder, IImageProcessor imageProcessor, IHttpClient httpClient)
+ : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, channelManager, subtitleEncoder)
{
ImageProcessor = imageProcessor;
HttpClient = httpClient;
@@ -52,23 +54,23 @@ namespace MediaBrowser.Api.Playback.Progressive
if (isVideoRequest)
{
var videoCodec = state.VideoRequest.VideoCodec;
-
- if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
- {
- return ".ts";
- }
- if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
- {
- return ".ogv";
- }
- if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
- {
- return ".webm";
- }
- if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
- {
- return ".asf";
- }
+
+ if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
+ {
+ return ".ts";
+ }
+ if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase))
+ {
+ return ".ogv";
+ }
+ if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase))
+ {
+ return ".webm";
+ }
+ if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase))
+ {
+ return ".asf";
+ }
}
// Try to infer based on the desired audio codec
@@ -153,7 +155,20 @@ namespace MediaBrowser.Api.Playback.Progressive
{
var throttleLimit = state.InputBitrate.HasValue ? (state.InputBitrate.Value / 8) : 0;
- return ResultFactory.GetStaticFileResult(Request, state.MediaPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest, request.Throttle, throttleLimit);
+ return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ {
+ ResponseHeaders = responseHeaders,
+ ContentType = contentType,
+ IsHeadRequest = isHeadRequest,
+ Path = state.MediaPath,
+ Throttle = request.Throttle,
+
+ // Pad by 20% to play it safe
+ ThrottleLimit = Convert.ToInt64(1.2 * throttleLimit),
+
+ // Three minutes
+ MinThrottlePosition = throttleLimit * 180
+ });
}
}
@@ -164,7 +179,13 @@ namespace MediaBrowser.Api.Playback.Progressive
try
{
- return ResultFactory.GetStaticFileResult(Request, outputPath, contentType, null, FileShare.Read, responseHeaders, isHeadRequest);
+ return ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
+ {
+ ResponseHeaders = responseHeaders,
+ ContentType = contentType,
+ IsHeadRequest = isHeadRequest,
+ Path = outputPath
+ });
}
finally
{
diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs
index 29cc7baf8..d6c854734 100644
--- a/MediaBrowser.Api/PluginService.cs
+++ b/MediaBrowser.Api/PluginService.cs
@@ -7,12 +7,12 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Serialization;
using ServiceStack;
+using ServiceStack.Text.Controller;
+using ServiceStack.Web;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using ServiceStack.Text.Controller;
-using ServiceStack.Web;
namespace MediaBrowser.Api
{
@@ -190,8 +190,7 @@ namespace MediaBrowser.Api
var result = new PluginSecurityInfo
{
IsMBSupporter = _securityManager.IsMBSupporter,
- SupporterKey = _securityManager.SupporterKey,
- LegacyKey = _securityManager.LegacyKey
+ SupporterKey = _securityManager.SupporterKey
};
return ToOptimizedSerializedResultUsingCache(result);
@@ -206,7 +205,6 @@ namespace MediaBrowser.Api
var info = request;
_securityManager.SupporterKey = info.SupporterKey;
- _securityManager.LegacyKey = info.LegacyKey;
}
/// <summary>
diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs
index cae648ae0..bac99c848 100644
--- a/MediaBrowser.Api/System/SystemService.cs
+++ b/MediaBrowser.Api/System/SystemService.cs
@@ -1,8 +1,10 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Security;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Net;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.System;
using ServiceStack;
using System;
@@ -42,6 +44,7 @@ namespace MediaBrowser.Api.System
/// This is currently not authenticated because the uninstaller needs to be able to shutdown the server.
/// </summary>
[Route("/System/Shutdown", "POST", Summary = "Shuts down the application")]
+ [Authenticated(AllowLocal = true)]
public class ShutdownApplication
{
}
@@ -66,6 +69,12 @@ namespace MediaBrowser.Api.System
public string Name { get; set; }
}
+ [Route("/System/SupporterInfo", "GET")]
+ [Authenticated]
+ public class GetSupporterInfo : IReturn<SupporterInfo>
+ {
+ }
+
/// <summary>
/// Class SystemInfoService
/// </summary>
@@ -80,6 +89,8 @@ namespace MediaBrowser.Api.System
private readonly INetworkManager _network;
+ private readonly ISecurityManager _security;
+
/// <summary>
/// Initializes a new instance of the <see cref="SystemService" /> class.
/// </summary>
@@ -87,12 +98,20 @@ namespace MediaBrowser.Api.System
/// <param name="appPaths">The application paths.</param>
/// <param name="fileSystem">The file system.</param>
/// <exception cref="ArgumentNullException">jsonSerializer</exception>
- public SystemService(IServerApplicationHost appHost, IApplicationPaths appPaths, IFileSystem fileSystem, INetworkManager network)
+ public SystemService(IServerApplicationHost appHost, IApplicationPaths appPaths, IFileSystem fileSystem, INetworkManager network, ISecurityManager security)
{
_appHost = appHost;
_appPaths = appPaths;
_fileSystem = fileSystem;
_network = network;
+ _security = security;
+ }
+
+ public async Task<object> Get(GetSupporterInfo request)
+ {
+ var result = await _security.GetSupporterInfo().ConfigureAwait(false);
+
+ return ToOptimizedResult(result);
}
public object Get(GetServerLogs request)
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index abb2f2089..4b0c95616 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -99,9 +99,9 @@
<Compile Include="ScheduledTasks\Tasks\ReloadLoggerFileTask.cs" />
<Compile Include="ScheduledTasks\Tasks\SystemUpdateTask.cs" />
<Compile Include="Security\MBLicenseFile.cs" />
- <Compile Include="Security\MBRegistration.cs" />
<Compile Include="Security\PluginSecurityManager.cs" />
<Compile Include="Security\RegRecord.cs" />
+ <Compile Include="Security\SuppporterInfoResponse.cs" />
<Compile Include="Serialization\JsonSerializer.cs" />
<Compile Include="Serialization\XmlSerializer.cs" />
<Compile Include="Updates\InstallationManager.cs" />
@@ -135,4 +135,4 @@ xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project> \ No newline at end of file
diff --git a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
index 77a7bf0f6..8f3225f4e 100644
--- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
+++ b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
@@ -1,7 +1,10 @@
using MediaBrowser.Common.Configuration;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
+using System.Linq;
using System.Security.Cryptography;
using System.Text;
@@ -19,7 +22,7 @@ namespace MediaBrowser.Common.Implementations.Security
if (value != _regKey)
{
//if key is changed - clear out our saved validations
- UpdateRecords.Clear();
+ _updateRecords.Clear();
_regKey = value;
}
}
@@ -33,24 +36,30 @@ namespace MediaBrowser.Common.Implementations.Security
}
}
- public string LegacyKey { get; set; }
- private Dictionary<Guid, DateTime> UpdateRecords { get; set; }
- private readonly object _lck = new object();
+ private readonly ConcurrentDictionary<Guid, DateTime> _updateRecords = new ConcurrentDictionary<Guid, DateTime>();
+ private readonly object _fileLock = new object();
private string _regKey;
public MBLicenseFile(IApplicationPaths appPaths)
{
_appPaths = appPaths;
- UpdateRecords = new Dictionary<Guid, DateTime>();
Load();
}
+ private void SetUpdateRecord(Guid key, DateTime value)
+ {
+ _updateRecords.AddOrUpdate(key, value, (k, v) => value);
+ }
+
public void AddRegCheck(string featureId)
{
using (var provider = new MD5CryptoServiceProvider())
{
- UpdateRecords[new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId)))] = DateTime.UtcNow;
+ var key = new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId)));
+ var value = DateTime.UtcNow;
+
+ SetUpdateRecord(key, value);
Save();
}
@@ -60,7 +69,11 @@ namespace MediaBrowser.Common.Implementations.Security
{
using (var provider = new MD5CryptoServiceProvider())
{
- UpdateRecords.Remove(new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))));
+ var key = new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId)));
+ DateTime val;
+
+ _updateRecords.TryRemove(key, out val);
+
Save();
}
@@ -71,8 +84,10 @@ namespace MediaBrowser.Common.Implementations.Security
using (var provider = new MD5CryptoServiceProvider())
{
DateTime last;
- lock(_lck) UpdateRecords.TryGetValue(new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))), out last);
- return last < DateTime.UtcNow ? last : DateTime.MinValue; // guard agains people just putting a large number in the file
+ _updateRecords.TryGetValue(new Guid(provider.ComputeHash(Encoding.Unicode.GetBytes(featureId))), out last);
+
+ // guard agains people just putting a large number in the file
+ return last < DateTime.UtcNow ? last : DateTime.MinValue;
}
}
@@ -80,7 +95,7 @@ namespace MediaBrowser.Common.Implementations.Security
{
string[] contents = null;
var licenseFile = Filename;
- lock (_lck)
+ lock (_fileLock)
{
try
{
@@ -95,13 +110,19 @@ namespace MediaBrowser.Common.Implementations.Security
{
//first line is reg key
RegKey = contents[0];
+
//next is legacy key
- if (contents.Length > 1) LegacyKey = contents[1];
+ if (contents.Length > 1)
+ {
+ // Don't need this anymore
+ }
+
//the rest of the lines should be pairs of features and timestamps
for (var i = 2; i < contents.Length; i = i + 2)
{
var feat = Guid.Parse(contents[i]);
- UpdateRecords[feat] = new DateTime(Convert.ToInt64(contents[i + 1]));
+
+ SetUpdateRecord(feat, new DateTime(Convert.ToInt64(contents[i + 1])));
}
}
}
@@ -109,16 +130,24 @@ namespace MediaBrowser.Common.Implementations.Security
public void Save()
{
//build our array
- var lines = new List<string> {RegKey, LegacyKey};
- foreach (var pair in UpdateRecords)
+ var lines = new List<string>
+ {
+ RegKey,
+
+ // Legacy key
+ string.Empty
+ };
+
+ foreach (var pair in _updateRecords
+ .ToList())
{
lines.Add(pair.Key.ToString());
- lines.Add(pair.Value.Ticks.ToString());
+ lines.Add(pair.Value.Ticks.ToString(CultureInfo.InvariantCulture));
}
var licenseFile = Filename;
Directory.CreateDirectory(Path.GetDirectoryName(licenseFile));
- lock (_lck) File.WriteAllLines(licenseFile, lines);
+ lock (_fileLock) File.WriteAllLines(licenseFile, lines);
}
}
}
diff --git a/MediaBrowser.Common.Implementations/Security/MBRegistration.cs b/MediaBrowser.Common.Implementations/Security/MBRegistration.cs
deleted file mode 100644
index dbb1b13e1..000000000
--- a/MediaBrowser.Common.Implementations/Security/MBRegistration.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Common.Implementations.Security
-{
- public static class MBRegistration
- {
-
- private static MBLicenseFile _licenseFile;
- private const string MBValidateUrl = Constants.Constants.MbAdminUrl + "service/registration/validate";
-
- private static IApplicationPaths _appPaths;
- private static INetworkManager _networkManager;
- private static ILogger _logger;
- private static IApplicationHost _applicationHost;
-
- private static MBLicenseFile LicenseFile
- {
- get { return _licenseFile ?? (_licenseFile = new MBLicenseFile(_appPaths)); }
- }
-
- public static string SupporterKey
- {
- get { return LicenseFile.RegKey; }
- set { LicenseFile.RegKey = value; LicenseFile.Save(); }
- }
-
- public static string LegacyKey
- {
- get { return LicenseFile.LegacyKey; }
- set { LicenseFile.LegacyKey = value; LicenseFile.Save(); }
- }
-
- public static void Init(IApplicationPaths appPaths, INetworkManager networkManager, ILogManager logManager, IApplicationHost appHost)
- {
- // Ugly alert (static init)
-
- _appPaths = appPaths;
- _networkManager = networkManager;
- _logger = logManager.GetLogger("SecurityManager");
- _applicationHost = appHost;
- }
-
- public static async Task<MBRegistrationRecord> GetRegistrationStatus(IHttpClient httpClient, IJsonSerializer jsonSerializer, string feature, string mb2Equivalent = null, string version = null)
- {
- //check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho
- var reg = new RegRecord { registered = LicenseFile.LastChecked(feature) > DateTime.UtcNow.AddDays(-30) };
- var success = reg.registered;
-
- if (!reg.registered)
- {
- var mac = _networkManager.GetMacAddress();
- var data = new Dictionary<string, string>
- {
- { "feature", feature },
- { "key", SupporterKey },
- { "mac", mac },
- { "mb2equiv", mb2Equivalent },
- { "legacykey", LegacyKey },
- { "ver", version },
- { "platform", Environment.OSVersion.VersionString },
- { "isservice", _applicationHost.IsRunningAsService.ToString().ToLower() }
- };
-
- try
- {
- using (var json = await httpClient.Post(MBValidateUrl, data, CancellationToken.None).ConfigureAwait(false))
- {
- reg = jsonSerializer.DeserializeFromStream<RegRecord>(json);
- success = true;
- }
-
- if (reg.registered)
- {
- LicenseFile.AddRegCheck(feature);
- }
- else
- {
- LicenseFile.RemoveRegCheck(feature);
- }
-
- }
- catch (Exception e)
- {
- _logger.ErrorException("Error checking registration status of {0}", e, feature);
- }
- }
-
- return new MBRegistrationRecord { IsRegistered = reg.registered, ExpirationDate = reg.expDate, RegChecked = true, RegError = !success};
- }
- }
-}
diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
index d0b108c7d..22fce1ce1 100644
--- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
+++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
@@ -17,6 +17,8 @@ namespace MediaBrowser.Common.Implementations.Security
/// </summary>
public class PluginSecurityManager : ISecurityManager
{
+ private const string MBValidateUrl = Constants.Constants.MbAdminUrl + "service/registration/validate";
+
/// <summary>
/// The _is MB supporter
/// </summary>
@@ -38,16 +40,23 @@ namespace MediaBrowser.Common.Implementations.Security
{
get
{
- LazyInitializer.EnsureInitialized(ref _isMbSupporter, ref _isMbSupporterInitialized, ref _isMbSupporterSyncLock, () => GetRegistrationStatus("MBSupporter", null, _appHost.ApplicationVersion.ToString()).Result.IsRegistered);
+ LazyInitializer.EnsureInitialized(ref _isMbSupporter, ref _isMbSupporterInitialized, ref _isMbSupporterSyncLock, () => GetSupporterRegistrationStatus().Result.IsRegistered);
return _isMbSupporter.Value;
}
}
+ private MBLicenseFile _licenseFile;
+ private MBLicenseFile LicenseFile
+ {
+ get { return _licenseFile ?? (_licenseFile = new MBLicenseFile(_appPaths)); }
+ }
+
private readonly IHttpClient _httpClient;
private readonly IJsonSerializer _jsonSerializer;
private readonly IApplicationHost _appHost;
- private readonly IApplicationPaths _applciationPaths;
+ private readonly ILogger _logger;
private readonly INetworkManager _networkManager;
+ private readonly IApplicationPaths _appPaths;
private IEnumerable<IRequiresRegistration> _registeredEntities;
protected IEnumerable<IRequiresRegistration> RegisteredEntities
@@ -69,12 +78,12 @@ namespace MediaBrowser.Common.Implementations.Security
throw new ArgumentNullException("httpClient");
}
- _applciationPaths = appPaths;
- _networkManager = networkManager;
_appHost = appHost;
_httpClient = httpClient;
_jsonSerializer = jsonSerializer;
- MBRegistration.Init(_applciationPaths, _networkManager, logManager, _appHost);
+ _networkManager = networkManager;
+ _appPaths = appPaths;
+ _logger = logManager.GetLogger("SecurityManager");
}
/// <summary>
@@ -97,9 +106,9 @@ namespace MediaBrowser.Common.Implementations.Security
/// <param name="feature">The feature.</param>
/// <param name="mb2Equivalent">The MB2 equivalent.</param>
/// <returns>Task{MBRegistrationRecord}.</returns>
- public async Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null)
+ public Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null)
{
- return await MBRegistration.GetRegistrationStatus(_httpClient, _jsonSerializer, feature, mb2Equivalent).ConfigureAwait(false);
+ return GetRegistrationStatusInternal(feature, mb2Equivalent);
}
/// <summary>
@@ -109,9 +118,14 @@ namespace MediaBrowser.Common.Implementations.Security
/// <param name="mb2Equivalent">The MB2 equivalent.</param>
/// <param name="version">The version of this feature</param>
/// <returns>Task{MBRegistrationRecord}.</returns>
- public async Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent, string version)
+ public Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent, string version)
{
- return await MBRegistration.GetRegistrationStatus(_httpClient, _jsonSerializer, feature, mb2Equivalent, version).ConfigureAwait(false);
+ return GetRegistrationStatusInternal(feature, mb2Equivalent, version);
+ }
+
+ private Task<MBRegistrationRecord> GetSupporterRegistrationStatus()
+ {
+ return GetRegistrationStatusInternal("MBSupporter", null, _appHost.ApplicationVersion.ToString());
}
/// <summary>
@@ -122,38 +136,130 @@ namespace MediaBrowser.Common.Implementations.Security
{
get
{
- return MBRegistration.SupporterKey;
+ return LicenseFile.RegKey;
}
set
{
- if (value != MBRegistration.SupporterKey)
+ if (value != LicenseFile.RegKey)
{
- MBRegistration.SupporterKey = value;
+ LicenseFile.RegKey = value;
+ LicenseFile.Save();
+
// re-load registration info
Task.Run(() => LoadAllRegistrationInfo());
}
}
}
- /// <summary>
- /// Gets or sets the legacy key.
- /// </summary>
- /// <value>The legacy key.</value>
- public string LegacyKey
+ public async Task<SupporterInfo> GetSupporterInfo()
{
- get
+ var key = SupporterKey;
+
+ if (string.IsNullOrWhiteSpace(key))
{
- return MBRegistration.LegacyKey;
+ return new SupporterInfo();
}
- set
+
+ var url = Constants.Constants.MbAdminUrl + "/service/supporter/retrieve?key=" + key;
+
+ using (var stream = await _httpClient.Get(url, CancellationToken.None).ConfigureAwait(false))
{
- if (value != MBRegistration.LegacyKey)
+ var response = _jsonSerializer.DeserializeFromStream<SuppporterInfoResponse>(stream);
+
+
+ var info = new SupporterInfo
{
- MBRegistration.LegacyKey = value;
- // re-load registration info
- Task.Run(() => LoadAllRegistrationInfo());
+ Email = response.email,
+ PlanType = response.planType,
+ SupporterKey = response.supporterKey,
+ ExpirationDate = string.IsNullOrWhiteSpace(response.expDate) ? (DateTime?)null : DateTime.Parse(response.expDate),
+ RegistrationDate = DateTime.Parse(response.regDate),
+ IsActiveSupporter = IsMBSupporter
+ };
+
+ info.IsExpiredSupporter = info.ExpirationDate.HasValue && info.ExpirationDate < DateTime.UtcNow && !string.IsNullOrWhiteSpace(info.SupporterKey);
+
+ // TODO: Now that we've pulled this down, might as well update the cached suppoter registrationinfo?
+
+ return info;
+ }
+ }
+
+ private async Task<MBRegistrationRecord> GetRegistrationStatusInternal(string feature,
+ string mb2Equivalent = null,
+ string version = null)
+ {
+ //check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho
+ var reg = new RegRecord
+ {
+ registered = LicenseFile.LastChecked(feature) > DateTime.UtcNow.AddDays(-7)
+ };
+
+ var success = reg.registered;
+
+ if (!reg.registered)
+ {
+ var mac = _networkManager.GetMacAddress();
+ var data = new Dictionary<string, string>
+ {
+ { "feature", feature },
+ { "key", SupporterKey },
+ { "mac", mac },
+ { "mb2equiv", mb2Equivalent },
+ { "ver", version },
+ { "platform", Environment.OSVersion.VersionString },
+ { "isservice", _appHost.IsRunningAsService.ToString().ToLower() }
+ };
+
+ try
+ {
+ using (var json = await _httpClient.Post(MBValidateUrl, data, CancellationToken.None).ConfigureAwait(false))
+ {
+ reg = _jsonSerializer.DeserializeFromStream<RegRecord>(json);
+ success = true;
+ }
+
+ if (reg.registered)
+ {
+ LicenseFile.AddRegCheck(feature);
+ }
+ else
+ {
+ LicenseFile.RemoveRegCheck(feature);
+ }
+
}
+ catch (Exception e)
+ {
+ _logger.ErrorException("Error checking registration status of {0}", e, feature);
+ }
+ }
+
+ var record = new MBRegistrationRecord
+ {
+ IsRegistered = reg.registered,
+ ExpirationDate = reg.expDate,
+ RegChecked = true,
+ RegError = !success
+ };
+
+ record.TrialVersion = IsInTrial(reg.expDate, record.RegChecked, record.IsRegistered);
+ record.IsValid = !record.RegChecked || (record.IsRegistered || record.TrialVersion);
+
+ return record;
+ }
+
+ private bool IsInTrial(DateTime expirationDate, bool regChecked, bool isRegistered)
+ {
+ //don't set this until we've successfully obtained exp date
+ if (!regChecked)
+ {
+ return false;
}
+
+ var isInTrial = expirationDate > DateTime.UtcNow;
+
+ return (isInTrial && !isRegistered);
}
/// <summary>
diff --git a/MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs b/MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs
new file mode 100644
index 000000000..49c5af8d8
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Security/SuppporterInfoResponse.cs
@@ -0,0 +1,14 @@
+
+namespace MediaBrowser.Common.Implementations.Security
+{
+ internal class SuppporterInfoResponse
+ {
+ public string email { get; set; }
+ public string supporterKey { get; set; }
+ public int totalRegs { get; set; }
+ public int totalMachines { get; set; }
+ public string expDate { get; set; }
+ public string regDate { get; set; }
+ public string planType { get; set; }
+ }
+}
diff --git a/MediaBrowser.Common/Security/ISecurityManager.cs b/MediaBrowser.Common/Security/ISecurityManager.cs
index 1555f1d86..935454353 100644
--- a/MediaBrowser.Common/Security/ISecurityManager.cs
+++ b/MediaBrowser.Common/Security/ISecurityManager.cs
@@ -1,5 +1,5 @@
-using System.Threading.Tasks;
using MediaBrowser.Model.Entities;
+using System.Threading.Tasks;
namespace MediaBrowser.Common.Security
{
@@ -18,17 +18,10 @@ namespace MediaBrowser.Common.Security
string SupporterKey { get; set; }
/// <summary>
- /// Gets or sets the legacy key.
- /// </summary>
- /// <value>The legacy key.</value>
- string LegacyKey { get; set; }
-
- /// <summary>
/// Gets the registration status. Overload to support existing plug-ins.
/// </summary>
/// <param name="feature">The feature.</param>
/// <param name="mb2Equivalent">The MB2 equivalent.</param>
- /// <param name="version">The version of the feature</param>
/// <returns>Task{MBRegistrationRecord}.</returns>
Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null);
@@ -40,10 +33,17 @@ namespace MediaBrowser.Common.Security
/// <param name="version">The version of the feature</param>
/// <returns>Task{MBRegistrationRecord}.</returns>
Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent, string version);
+
/// <summary>
/// Load all registration info for all entities that require registration
/// </summary>
/// <returns></returns>
Task LoadAllRegistrationInfo();
+
+ /// <summary>
+ /// Gets the supporter information.
+ /// </summary>
+ /// <returns>Task&lt;SupporterInfo&gt;.</returns>
+ Task<SupporterInfo> GetSupporterInfo();
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index b13403bbf..25d41565a 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Entities.Audio
Tags = new List<string>();
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
@@ -118,6 +119,7 @@ namespace MediaBrowser.Controller.Entities.Audio
/// Gets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
+ [IgnoreDataMember]
public override string MediaType
{
get
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 2eeec9715..dc9f83b3c 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -22,6 +22,7 @@ namespace MediaBrowser.Controller.Entities.Audio
AlbumArtists = new List<string>();
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return true; }
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index de527b68b..070572b9b 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Progress;
+using System.Runtime.Serialization;
+using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
@@ -26,6 +27,7 @@ namespace MediaBrowser.Controller.Entities.Audio
}
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return true; }
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index f1dc56ac6..928eb6463 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.Serialization;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -18,6 +19,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return "MusicGenre-" + Name;
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return true; }
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index fd7a33ddf..26b28ec72 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.Entities
public List<ItemImageInfo> ImageInfos { get; set; }
+ [IgnoreDataMember]
public virtual bool SupportsAddingToPlaylist
{
get
@@ -192,6 +193,7 @@ namespace MediaBrowser.Controller.Entities
}
}
+ [IgnoreDataMember]
public virtual bool SupportsLocalMetadata
{
get
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 1f38de9a3..367db5dcb 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -17,6 +17,7 @@ namespace MediaBrowser.Controller.Entities
Taglines = new List<string>();
}
+ [IgnoreDataMember]
public override bool SupportsLocalMetadata
{
get
@@ -25,6 +26,7 @@ namespace MediaBrowser.Controller.Entities
}
}
+ [IgnoreDataMember]
public override string MediaType
{
get
@@ -38,6 +40,16 @@ namespace MediaBrowser.Controller.Entities
{
get
{
+ return Album;
+ }
+ }
+
+
+ [IgnoreDataMember]
+ public PhotoAlbum Album
+ {
+ get
+ {
return Parents.OfType<PhotoAlbum>().FirstOrDefault();
}
}
@@ -53,6 +65,11 @@ namespace MediaBrowser.Controller.Entities
public double? Aperture { get; set; }
public double? ShutterSpeed { get; set; }
+ public double? Latitude { get; set; }
+ public double? Longitude { get; set; }
+ public double? Altitude { get; set; }
+ public int? IsoSpeedRating { get; set; }
+
protected override bool GetBlockUnratedValue(UserConfiguration config)
{
return config.BlockUnratedItems.Contains(UnratedItem.Other);
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index b82a400fe..6804b29b7 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return true; }
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 856ed4fdf..d3b95eb0c 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -39,6 +39,7 @@ namespace MediaBrowser.Controller.Entities.TV
DisplaySpecialsWithSeasons = true;
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return true; }
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index ea530272d..492a4a02f 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -58,6 +58,7 @@ namespace MediaBrowser.Controller.Entities
LinkedAlternateVersions = new List<LinkedChild>();
}
+ [IgnoreDataMember]
public override bool SupportsAddingToPlaylist
{
get { return LocationType == LocationType.FileSystem && RunTimeTicks.HasValue; }
@@ -238,6 +239,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
+ [IgnoreDataMember]
public override string MediaType
{
get
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index aeeaae073..6a78fa5d9 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -214,6 +214,7 @@
<Compile Include="Net\IRestfulService.cs" />
<Compile Include="Net\ISessionContext.cs" />
<Compile Include="Net\LoggedAttribute.cs" />
+ <Compile Include="Net\StaticResultOptions.cs" />
<Compile Include="News\INewsService.cs" />
<Compile Include="Notifications\INotificationManager.cs" />
<Compile Include="Notifications\INotificationService.cs" />
diff --git a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
index 567d20f39..329dbaa46 100644
--- a/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
+++ b/MediaBrowser.Controller/Net/AuthenticatedAttribute.cs
@@ -8,6 +8,12 @@ namespace MediaBrowser.Controller.Net
public IAuthService AuthService { get; set; }
/// <summary>
+ /// Gets or sets a value indicating whether or not to allow local unauthenticated access.
+ /// </summary>
+ /// <value><c>true</c> if [allow local]; otherwise, <c>false</c>.</value>
+ public bool AllowLocal { get; set; }
+
+ /// <summary>
/// The request filter is executed before the service.
/// </summary>
/// <param name="request">The http request wrapper</param>
@@ -15,7 +21,7 @@ namespace MediaBrowser.Controller.Net
/// <param name="requestDto">The request DTO</param>
public void RequestFilter(IRequest request, IResponse response, object requestDto)
{
- AuthService.Authenticate(request, response, requestDto);
+ AuthService.Authenticate(request, response, requestDto, AllowLocal);
}
/// <summary>
diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs
index 41859395b..dca70f58f 100644
--- a/MediaBrowser.Controller/Net/IAuthService.cs
+++ b/MediaBrowser.Controller/Net/IAuthService.cs
@@ -4,6 +4,6 @@ namespace MediaBrowser.Controller.Net
{
public interface IAuthService
{
- void Authenticate(IRequest request, IResponse response, object requestDto);
+ void Authenticate(IRequest request, IResponse response, object requestDto, bool allowLocal);
}
}
diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
index f0cfbbcfa..526bf4be2 100644
--- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs
+++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs
@@ -1,8 +1,8 @@
-using System;
+using ServiceStack.Web;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
-using ServiceStack.Web;
namespace MediaBrowser.Controller.Net
{
@@ -89,47 +89,29 @@ namespace MediaBrowser.Controller.Net
bool isHeadRequest = false);
/// <summary>
- /// Gets the static file result.
+ /// Gets the static result.
/// </summary>
/// <param name="requestContext">The request context.</param>
- /// <param name="path">The path.</param>
- /// <param name="fileShare">The file share.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
+ /// <param name="options">The options.</param>
/// <returns>System.Object.</returns>
- object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read, IDictionary<string, string> responseHeaders = null, bool isHeadRequest = false);
+ object GetStaticResult(IRequest requestContext, StaticResultOptions options);
/// <summary>
/// Gets the static file result.
/// </summary>
/// <param name="requestContext">The request context.</param>
/// <param name="path">The path.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="cacheCuration">The cache curation.</param>
/// <param name="fileShare">The file share.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <param name="throttle">if set to <c>true</c> [throttle].</param>
- /// <param name="throttleLimit">The throttle limit.</param>
/// <returns>System.Object.</returns>
- object GetStaticFileResult(IRequest requestContext,
- string path,
- string contentType,
- TimeSpan? cacheCuration = null,
- FileShare fileShare = FileShare.Read,
- IDictionary<string, string> responseHeaders = null,
- bool isHeadRequest = false,
- bool throttle = false,
- long throttleLimit = 0);
-
+ object GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read);
+
/// <summary>
- /// Gets the optimized serialized result using cache.
+ /// Gets the static file result.
/// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="request">The request.</param>
- /// <param name="result">The result.</param>
+ /// <param name="requestContext">The request context.</param>
+ /// <param name="options">The options.</param>
/// <returns>System.Object.</returns>
- object GetOptimizedSerializedResultUsingCache<T>(IRequest request, T result)
- where T : class;
+ object GetStaticFileResult(IRequest requestContext,
+ StaticFileResultOptions options);
}
}
diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs
new file mode 100644
index 000000000..fde08c269
--- /dev/null
+++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.Net
+{
+ public class StaticResultOptions
+ {
+ public string ContentType { get; set; }
+ public TimeSpan? CacheDuration { get; set; }
+ public DateTime? DateLastModified { get; set; }
+ public Guid CacheKey { get; set; }
+
+ public Func<Task<Stream>> ContentFactory { get; set; }
+
+ public bool IsHeadRequest { get; set; }
+
+ public IDictionary<string, string> ResponseHeaders { get; set; }
+
+ public bool Throttle { get; set; }
+ public long ThrottleLimit { get; set; }
+ public long MinThrottlePosition { get; set; }
+
+ public StaticResultOptions()
+ {
+ ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ }
+ }
+
+ public class StaticFileResultOptions : StaticResultOptions
+ {
+ public string Path { get; set; }
+
+ public FileShare FileShare { get; set; }
+
+ public StaticFileResultOptions()
+ {
+ FileShare = FileShare.Read;
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index 6d5ed9eb8..3d08159d6 100644
--- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -190,6 +190,8 @@ namespace MediaBrowser.Dlna.ContentDirectory
if (string.Equals(flag, "BrowseMetadata"))
{
+
+
var folder = item as Folder;
if (folder == null)
@@ -198,10 +200,12 @@ namespace MediaBrowser.Dlna.ContentDirectory
}
else
{
+
+
var childrenResult = (await GetChildrenSorted(folder, user, sortCriteria, start, requested).ConfigureAwait(false));
totalCount = childrenResult.TotalRecordCount;
- result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, folder, totalCount, filter));
+ result.DocumentElement.AppendChild(_didlBuilder.GetFolderElement(result, folder, totalCount, filter, id));
}
provided++;
}
@@ -531,10 +535,7 @@ namespace MediaBrowser.Dlna.ContentDirectory
private BaseItem GetItemFromObjectId(string id, User user)
{
- return string.IsNullOrWhiteSpace(id) || string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
-
- // Samsung sometimes uses 1 as root
- || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase)
+ return DidlBuilder.IsIdRoot(id)
? user.RootFolder
: ParseItemId(id, user);
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 69fec1e44..53fac9a93 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -362,22 +362,46 @@ namespace MediaBrowser.Dlna.Didl
container.AppendChild(res);
}
- public XmlElement GetFolderElement(XmlDocument doc, Folder folder, int childCount, Filter filter)
+ public static bool IsIdRoot(string id)
+ {
+ if (string.IsNullOrWhiteSpace(id) ||
+
+ string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
+
+ // Samsung sometimes uses 1 as root
+ || string.Equals(id, "1", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public XmlElement GetFolderElement(XmlDocument doc, Folder folder, int childCount, Filter filter, string requestedId = null)
{
var container = doc.CreateElement(string.Empty, "container", NS_DIDL);
container.SetAttribute("restricted", "0");
container.SetAttribute("searchable", "1");
container.SetAttribute("childCount", childCount.ToString(_usCulture));
- container.SetAttribute("id", folder.Id.ToString("N"));
- var parent = folder.Parent;
- if (parent == null)
+ if (string.Equals(requestedId, "0"))
{
- container.SetAttribute("parentID", "0");
+ container.SetAttribute("id", "0");
+ container.SetAttribute("parentID", "-1");
}
else
{
- container.SetAttribute("parentID", parent.Id.ToString("N"));
+ container.SetAttribute("id", folder.Id.ToString("N"));
+
+ var parent = folder.Parent;
+ if (parent == null)
+ {
+ container.SetAttribute("parentID", "0");
+ }
+ else
+ {
+ container.SetAttribute("parentID", parent.Id.ToString("N"));
+ }
}
AddCommonFields(folder, container, filter);
diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
index b8c64a787..a237a0d67 100644
--- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
+++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
@@ -170,7 +170,10 @@ namespace MediaBrowser.Dlna.Ssdp
values["ST"] = d.Type;
values["USN"] = d.USN;
- SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0));
+ // Commenting this out because binding to the local ipendpoint often throws an error
+ //SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0));
+
+ SendDatagram(header, values, endpoint, null);
if (_config.GetDlnaConfiguration().EnableDebugLogging)
{
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index 9263a3187..22873d910 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -62,6 +62,7 @@
<Compile Include="Subtitles\ISubtitleParser.cs" />
<Compile Include="Subtitles\ISubtitleWriter.cs" />
<Compile Include="Subtitles\JsonWriter.cs" />
+ <Compile Include="Subtitles\ParserValues.cs" />
<Compile Include="Subtitles\SrtParser.cs" />
<Compile Include="Subtitles\SrtWriter.cs" />
<Compile Include="Subtitles\AssParser.cs" />
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
index e5a727428..aaaafc226 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Common.Extensions;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -42,6 +43,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]);
subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]);
subEvent.Text = string.Join(",", sections.Skip(headers["Text"]));
+ subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
trackInfo.TrackEvents.Add(subEvent);
diff --git a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs
new file mode 100644
index 000000000..d79aeee76
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.MediaEncoding.Subtitles
+{
+ public class ParserValues
+ {
+ public const string NewLine = "\r\n";
+ }
+}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
index 84cd1eb2d..ea565f70a 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
+using MediaBrowser.Common.Extensions;
namespace MediaBrowser.MediaEncoding.Subtitles
{
@@ -48,7 +49,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
multiline.Add(line);
}
- subEvent.Text = string.Join(@"\n", multiline);
+ subEvent.Text = string.Join(ParserValues.NewLine, multiline);
+ subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, "<", "&lt;", RegexOptions.IgnoreCase);
subEvent.Text = Regex.Replace(subEvent.Text, ">", "&gt;", RegexOptions.IgnoreCase);
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
index 559a05bc8..d82ef4e24 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Common.Extensions;
+using System;
using System.IO;
using System.Text;
using System.Threading;
@@ -147,7 +148,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
public static string GetFormattedText(string text)
{
- text = text.Replace("\\n", Environment.NewLine).Replace("\\n", Environment.NewLine);
+ text = text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase)
+ .Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
+
bool italic = false;
for (int i = 0; i < 10; i++) // just look ten times...
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index df22b5e1f..7a3a7d2d0 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -194,17 +194,38 @@ namespace MediaBrowser.MediaEncoding.Subtitles
MediaStream subtitleStream,
CancellationToken cancellationToken)
{
- const string extractedFormat = "srt";
-
if (!subtitleStream.IsExternal)
{
+ string outputFormat;
+ string outputCodec;
+
+ if (string.Equals(subtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase))
+ {
+ // Extract
+ outputCodec = "copy";
+ outputFormat = "ass";
+ }
+ else if (string.Equals(subtitleStream.Codec, "subrip", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(subtitleStream.Codec, "srt", StringComparison.OrdinalIgnoreCase))
+ {
+ // Extract
+ outputCodec = "copy";
+ outputFormat = "srt";
+ }
+ else
+ {
+ // Extract
+ outputCodec = "srt";
+ outputFormat = "srt";
+ }
+
// Extract
- var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat);
+ var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + outputFormat);
- await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken)
+ await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
.ConfigureAwait(false);
- return new Tuple<string, string>(outputPath, extractedFormat);
+ return new Tuple<string, string>(outputPath, outputFormat);
}
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
@@ -213,12 +234,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (GetReader(currentFormat, false) == null)
{
// Convert
- var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, "." + extractedFormat);
+ var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".srt");
await ConvertTextSubtitleToSrt(subtitleStream.Path, outputPath, subtitleStream.Language, cancellationToken)
.ConfigureAwait(false);
- return new Tuple<string, string>(outputPath, extractedFormat);
+ return new Tuple<string, string>(outputPath, "srt");
}
return new Tuple<string, string>(subtitleStream.Path, currentFormat);
@@ -477,13 +498,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <param name="inputFiles">The input files.</param>
/// <param name="protocol">The protocol.</param>
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
- /// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
+ /// <param name="outputCodec">The output codec.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex,
- bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
+ string outputCodec, string outputPath, CancellationToken cancellationToken)
{
var semaphore = GetLock(outputPath);
@@ -494,7 +515,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (!File.Exists(outputPath))
{
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex,
- copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
+ outputCodec, outputPath, cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -503,23 +524,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
- /// <summary>
- /// Extracts the text subtitle.
- /// </summary>
- /// <param name="inputPath">The input path.</param>
- /// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
- /// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
- /// <param name="outputPath">The output path.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- /// <exception cref="System.ArgumentNullException">inputPath
- /// or
- /// outputPath
- /// or
- /// cancellationToken</exception>
- /// <exception cref="System.ApplicationException"></exception>
private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex,
- bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
+ string outputCodec, string outputPath, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(inputPath))
{
@@ -533,14 +539,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
- var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s srt \"{2}\"", inputPath,
- subtitleStreamIndex, outputPath);
-
- if (copySubtitleStream)
- {
- processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s copy \"{2}\"", inputPath,
- subtitleStreamIndex, outputPath);
- }
+ var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath,
+ subtitleStreamIndex, outputCodec, outputPath);
var process = new Process
{
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 360d2d862..ec5a26eee 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -732,7 +732,11 @@ namespace MediaBrowser.Model.Dto
public ImageOrientation? ImageOrientation { get; set; }
public double? Aperture { get; set; }
public double? ShutterSpeed { get; set; }
-
+ public double? Latitude { get; set; }
+ public double? Longitude { get; set; }
+ public double? Altitude { get; set; }
+ public int? IsoSpeedRating { get; set; }
+
/// <summary>
/// Gets a value indicating whether this instance can resume.
/// </summary>
diff --git a/MediaBrowser.Model/Entities/MBRegistrationRecord.cs b/MediaBrowser.Model/Entities/MBRegistrationRecord.cs
index e72a5011c..3a4af19d8 100644
--- a/MediaBrowser.Model/Entities/MBRegistrationRecord.cs
+++ b/MediaBrowser.Model/Entities/MBRegistrationRecord.cs
@@ -5,25 +5,21 @@ namespace MediaBrowser.Model.Entities
public class MBRegistrationRecord
{
public DateTime ExpirationDate { get; set; }
- public bool IsRegistered { get; set;}
+ public bool IsRegistered { get; set; }
public bool RegChecked { get; set; }
public bool RegError { get; set; }
- private bool? _isInTrial;
- public bool TrialVersion
- {
- get
- {
- if (_isInTrial == null)
- {
- if (!RegChecked) return false; //don't set this until we've successfully obtained exp date
- _isInTrial = ExpirationDate > DateTime.Now;
- }
- return (_isInTrial.Value && !IsRegistered);
- }
- }
- public bool IsValid
- {
- get { return !RegChecked || (IsRegistered || TrialVersion); }
- }
+ public bool TrialVersion { get; set; }
+ public bool IsValid { get; set; }
+ }
+
+ public class SupporterInfo
+ {
+ public string Email { get; set; }
+ public string SupporterKey { get; set; }
+ public DateTime? ExpirationDate { get; set; }
+ public DateTime RegistrationDate { get; set; }
+ public string PlanType { get; set; }
+ public bool IsActiveSupporter { get; set; }
+ public bool IsExpiredSupporter { get; set; }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Entities/PluginSecurityInfo.cs b/MediaBrowser.Model/Entities/PluginSecurityInfo.cs
index e338e43f8..5cab55013 100644
--- a/MediaBrowser.Model/Entities/PluginSecurityInfo.cs
+++ b/MediaBrowser.Model/Entities/PluginSecurityInfo.cs
@@ -13,12 +13,6 @@ namespace MediaBrowser.Model.Entities
public string SupporterKey { get; set; }
/// <summary>
- /// Gets or sets the legacy supporter key.
- /// </summary>
- /// <value><c>The legacy supporter key</value>
- public string LegacyKey { get; set; }
-
- /// <summary>
/// Gets or sets a value indicating whether this instance is MB supporter.
/// </summary>
/// <value><c>true</c> if this instance is MB supporter; otherwise, <c>false</c>.</value>
diff --git a/MediaBrowser.Providers/Photos/PhotoProvider.cs b/MediaBrowser.Providers/Photos/PhotoProvider.cs
index 123c91d07..b298c62e7 100644
--- a/MediaBrowser.Providers/Photos/PhotoProvider.cs
+++ b/MediaBrowser.Providers/Photos/PhotoProvider.cs
@@ -123,6 +123,19 @@ namespace MediaBrowser.Providers.Photos
item.ExposureTime = image.ImageTag.ExposureTime;
item.FocalLength = image.ImageTag.FocalLength;
+
+ item.Latitude = image.ImageTag.Latitude;
+ item.Longitude = image.ImageTag.Longitude;
+ item.Altitude = image.ImageTag.Altitude;
+
+ if (image.ImageTag.ISOSpeedRatings.HasValue)
+ {
+ item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value);
+ }
+ else
+ {
+ item.IsoSpeedRating = null;
+ }
}
catch (Exception e)
{
@@ -145,7 +158,7 @@ namespace MediaBrowser.Providers.Photos
public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
{
// Moved to plural AlbumArtists
- if (date < new DateTime(2014, 8, 28))
+ if (date < new DateTime(2014, 8, 29))
{
// Revamped vaptured metadata
return true;
diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
index 61517ce6e..922287f6e 100644
--- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs
+++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs
@@ -1,5 +1,4 @@
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.IO;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
@@ -369,6 +368,19 @@ namespace MediaBrowser.Server.Implementations.Dto
dto.ImageOrientation = item.Orientation;
dto.Aperture = item.Aperture;
dto.ShutterSpeed = item.ShutterSpeed;
+
+ dto.Latitude = item.Latitude;
+ dto.Longitude = item.Longitude;
+ dto.Altitude = item.Altitude;
+ dto.IsoSpeedRating = item.IsoSpeedRating;
+
+ var album = item.Album;
+
+ if (album != null)
+ {
+ dto.Album = item.Name;
+ dto.AlbumId = item.Id.ToString("N");
+ }
}
private void SetMusicVideoProperties(BaseItemDto dto, MusicVideo item)
diff --git a/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs b/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
index c2c4056f5..27170ced9 100644
--- a/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
+++ b/MediaBrowser.Server.Implementations/EntryPoints/LoadRegistrations.cs
@@ -2,6 +2,8 @@
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Logging;
using System;
+using System.Threading;
+using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.EntryPoints
{
@@ -20,6 +22,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// </summary>
private readonly ILogger _logger;
+ private Timer _timer;
+
/// <summary>
/// Initializes a new instance of the <see cref="LoadRegistrations" /> class.
/// </summary>
@@ -35,7 +39,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// <summary>
/// Runs this instance.
/// </summary>
- public async void Run()
+ public void Run()
+ {
+ _timer = new Timer(s => LoadAllRegistrations(), null, TimeSpan.FromMilliseconds(100), TimeSpan.FromHours(24));
+ }
+
+ private async Task LoadAllRegistrations()
{
try
{
@@ -52,6 +61,11 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
/// </summary>
public void Dispose()
{
+ if (_timer != null)
+ {
+ _timer.Dispose();
+ _timer = null;
+ }
}
}
}
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
index 1cec4461b..16ca8b099 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -14,6 +14,7 @@ using ServiceStack.Host.HttpListener;
using ServiceStack.Logging;
using ServiceStack.Web;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -39,13 +40,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected;
+ private readonly ConcurrentDictionary<string, string> _localEndPoints = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
/// <summary>
/// Gets the local end points.
/// </summary>
/// <value>The local end points.</value>
public IEnumerable<string> LocalEndPoints
{
- get { return _listener == null ? new List<string>() : _listener.LocalEndPoints; }
+ get { return _listener == null ? new List<string>() : _localEndPoints.Keys.ToList(); }
}
public HttpListenerHost(IApplicationHost applicationHost, ILogManager logManager, string serviceName, string handlerPath, string defaultRedirectPath, params Assembly[] assembliesWithServices)
@@ -151,6 +154,11 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return this;
}
+ private void OnRequestReceived(string localEndPoint)
+ {
+ _localEndPoints.GetOrAdd(localEndPoint, localEndPoint);
+ }
+
/// <summary>
/// Starts the Web Service
/// </summary>
@@ -159,9 +167,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First());
_listener = NativeWebSocket.IsSupported
- ? _listener = new HttpListenerServer(_logger)
+ ? _listener = new HttpListenerServer(_logger, OnRequestReceived)
//? _listener = new WebSocketSharpListener(_logger)
- : _listener = new WebSocketSharpListener(_logger);
+ : _listener = new WebSocketSharpListener(_logger, OnRequestReceived);
_listener.WebSocketHandler = WebSocketHandler;
_listener.ErrorHandler = ErrorHandler;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
index be3e5f005..9997cfbdb 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -289,41 +289,28 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return null;
}
- /// <summary>
- /// Gets the static file result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="path">The path.</param>
- /// <param name="fileShare">The file share.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <returns>System.Object.</returns>
- /// <exception cref="ArgumentNullException">path</exception>
- /// <exception cref="System.ArgumentNullException">path</exception>
public object GetStaticFileResult(IRequest requestContext,
string path,
- FileShare fileShare = FileShare.Read,
- IDictionary<string, string> responseHeaders = null,
- bool isHeadRequest = false)
+ FileShare fileShare = FileShare.Read)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
- return GetStaticFileResult(requestContext, path, MimeTypes.GetMimeType(path), null, fileShare, responseHeaders, isHeadRequest);
+ return GetStaticFileResult(requestContext, new StaticFileResultOptions
+ {
+ Path = path,
+ FileShare = fileShare
+ });
}
public object GetStaticFileResult(IRequest requestContext,
- string path,
- string contentType,
- TimeSpan? cacheCuration = null,
- FileShare fileShare = FileShare.Read,
- IDictionary<string, string> responseHeaders = null,
- bool isHeadRequest = false,
- bool throttle = false,
- long throttleLimit = 0)
+ StaticFileResultOptions options)
{
+ var path = options.Path;
+ var fileShare = options.FileShare;
+
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
@@ -334,11 +321,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer
throw new ArgumentException("FileShare must be either Read or ReadWrite");
}
- var dateModified = _fileSystem.GetLastWriteTimeUtc(path);
+ if (string.IsNullOrWhiteSpace(options.ContentType))
+ {
+ options.ContentType = MimeTypes.GetMimeType(path);
+ }
- var cacheKey = path + dateModified.Ticks;
+ options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
+ var cacheKey = path + options.DateLastModified.Value.Ticks;
- return GetStaticResult(requestContext, cacheKey.GetMD5(), dateModified, cacheCuration, contentType, () => Task.FromResult(GetFileStream(path, fileShare)), responseHeaders, isHeadRequest, throttle, throttleLimit);
+ options.CacheKey = cacheKey.GetMD5();
+ options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));
+
+ return GetStaticResult(requestContext, options);
}
/// <summary>
@@ -352,21 +346,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare, true);
}
- /// <summary>
- /// Gets the static result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="cacheKey">The cache key.</param>
- /// <param name="lastDateModified">The last date modified.</param>
- /// <param name="cacheDuration">Duration of the cache.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="factoryFn">The factory fn.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <returns>System.Object.</returns>
- /// <exception cref="System.ArgumentNullException">cacheKey
- /// or
- /// factoryFn</exception>
public object GetStaticResult(IRequest requestContext,
Guid cacheKey,
DateTime? lastDateModified,
@@ -376,39 +355,37 @@ namespace MediaBrowser.Server.Implementations.HttpServer
IDictionary<string, string> responseHeaders = null,
bool isHeadRequest = false)
{
- return GetStaticResult(requestContext, cacheKey, lastDateModified, cacheDuration, contentType, factoryFn,
- responseHeaders, isHeadRequest, false, 0);
+ return GetStaticResult(requestContext, new StaticResultOptions
+ {
+ CacheDuration = cacheDuration,
+ CacheKey = cacheKey,
+ ContentFactory = factoryFn,
+ ContentType = contentType,
+ DateLastModified = lastDateModified,
+ IsHeadRequest = isHeadRequest,
+ ResponseHeaders = responseHeaders
+ });
}
- public object GetStaticResult(IRequest requestContext,
- Guid cacheKey,
- DateTime? lastDateModified,
- TimeSpan? cacheDuration,
- string contentType,
- Func<Task<Stream>> factoryFn,
- IDictionary<string, string> responseHeaders = null,
- bool isHeadRequest = false,
- bool throttle = false,
- long throttleLimit = 0)
+ public object GetStaticResult(IRequest requestContext, StaticResultOptions options)
{
+ var cacheKey = options.CacheKey;
+ options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>();
+ var contentType = options.ContentType;
+
if (cacheKey == Guid.Empty)
{
throw new ArgumentNullException("cacheKey");
}
- if (factoryFn == null)
+ if (options.ContentFactory == null)
{
throw new ArgumentNullException("factoryFn");
}
var key = cacheKey.ToString("N");
- if (responseHeaders == null)
- {
- responseHeaders = new Dictionary<string, string>();
- }
-
// See if the result is already cached in the browser
- var result = GetCachedResult(requestContext, responseHeaders, cacheKey, key, lastDateModified, cacheDuration, contentType);
+ var result = GetCachedResult(requestContext, options.ResponseHeaders, cacheKey, key, options.DateLastModified, options.CacheDuration, contentType);
if (result != null)
{
@@ -416,8 +393,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
}
var compress = ShouldCompressResponse(requestContext, contentType);
- var hasOptions = GetStaticResult(requestContext, responseHeaders, contentType, factoryFn, compress, isHeadRequest, throttle, throttleLimit).Result;
- AddResponseHeaders(hasOptions, responseHeaders);
+ var hasOptions = GetStaticResult(requestContext, options, compress).Result;
+ AddResponseHeaders(hasOptions, options.ResponseHeaders);
return hasOptions;
}
@@ -473,20 +450,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer
/// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- /// <summary>
- /// Gets the static result.
- /// </summary>
- /// <param name="requestContext">The request context.</param>
- /// <param name="responseHeaders">The response headers.</param>
- /// <param name="contentType">Type of the content.</param>
- /// <param name="factoryFn">The factory fn.</param>
- /// <param name="compress">if set to <c>true</c> [compress].</param>
- /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <param name="throttle">if set to <c>true</c> [throttle].</param>
- /// <param name="throttleLimit">The throttle limit.</param>
- /// <returns>Task{IHasOptions}.</returns>
- private async Task<IHasOptions> GetStaticResult(IRequest requestContext, IDictionary<string, string> responseHeaders, string contentType, Func<Task<Stream>> factoryFn, bool compress, bool isHeadRequest, bool throttle, long throttleLimit = 0)
+ private async Task<IHasOptions> GetStaticResult(IRequest requestContext, StaticResultOptions options, bool compress)
{
+ var isHeadRequest = options.IsHeadRequest;
+ var factoryFn = options.ContentFactory;
+ var contentType = options.ContentType;
+ var responseHeaders = options.ResponseHeaders;
+
var requestedCompressionType = requestContext.GetCompressionType();
if (!compress || string.IsNullOrEmpty(requestedCompressionType))
@@ -499,8 +469,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
return new RangeRequestWriter(rangeHeader, stream, contentType, isHeadRequest)
{
- Throttle = throttle,
- ThrottleLimit = throttleLimit
+ Throttle = options.Throttle,
+ ThrottleLimit = options.ThrottleLimit,
+ MinThrottlePosition = options.MinThrottlePosition
};
}
@@ -515,8 +486,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer
return new StreamWriter(stream, contentType, _logger)
{
- Throttle = throttle,
- ThrottleLimit = throttleLimit
+ Throttle = options.Throttle,
+ ThrottleLimit = options.ThrottleLimit,
+ MinThrottlePosition = options.MinThrottlePosition
};
}
@@ -746,14 +718,5 @@ namespace MediaBrowser.Server.Implementations.HttpServer
throw error;
}
-
- public object GetOptimizedSerializedResultUsingCache<T>(IRequest request, T result)
- where T : class
- {
- var json = _jsonSerializer.SerializeToString(result);
- var cacheKey = json.GetMD5();
-
- return GetOptimizedResultUsingCache(request, cacheKey, null, null, () => result);
- }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
index 1d80a263c..86e8856cf 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/IHttpListener.cs
@@ -8,8 +8,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
public interface IHttpListener : IDisposable
{
- IEnumerable<string> LocalEndPoints { get; }
-
/// <summary>
/// Gets or sets the error handler.
/// </summary>
diff --git a/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs b/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
index bdc2750fb..118bec60e 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/NetListener/HttpListenerServer.cs
@@ -4,7 +4,6 @@ using ServiceStack;
using ServiceStack.Host.HttpListener;
using ServiceStack.Web;
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
@@ -20,26 +19,18 @@ namespace MediaBrowser.Server.Implementations.HttpServer.NetListener
private HttpListener _listener;
private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
- public System.Action<Exception, IRequest> ErrorHandler { get; set; }
+ public Action<Exception, IRequest> ErrorHandler { get; set; }
public Action<WebSocketConnectEventArgs> WebSocketHandler { get; set; }
- public System.Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
+ public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
- private readonly ConcurrentDictionary<string, string> _localEndPoints = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ private readonly Action<string> _endpointListener;
- public HttpListenerServer(ILogger logger)
+ public HttpListenerServer(ILogger logger, Action<string> endpointListener)
{
_logger = logger;
+ _endpointListener = endpointListener;
}
- /// <summary>
- /// Gets the local end points.
- /// </summary>
- /// <value>The local end points.</value>
- public IEnumerable<string> LocalEndPoints
- {
- get { return _localEndPoints.Keys.ToList(); }
- }
-
private List<string> UrlPrefixes { get; set; }
public void Start(IEnumerable<string> urlPrefixes)
@@ -47,7 +38,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.NetListener
UrlPrefixes = urlPrefixes.ToList();
if (_listener == null)
- _listener = new System.Net.HttpListener();
+ _listener = new HttpListener();
//HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First());
@@ -229,7 +220,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.NetListener
{
var address = endpoint.ToString();
- _localEndPoints.GetOrAdd(address, address);
+ _endpointListener(address);
}
LogRequest(_logger, request);
diff --git a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
index 5fd43aa76..657545069 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -26,6 +26,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public bool Throttle { get; set; }
public long ThrottleLimit { get; set; }
+ public long MinThrottlePosition;
/// <summary>
/// The _options
@@ -166,7 +167,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
{
- MinThrottlePosition = ThrottleLimit * 180
+ MinThrottlePosition = MinThrottlePosition
};
}
var task = WriteToAsync(responseStream);
diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
index 19870c435..2b9ae7d09 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
/// </summary>
public string HtmlRedirect { get; set; }
- public void Authenticate(IRequest req, IResponse res, object requestDto)
+ public void Authenticate(IRequest req, IResponse res, object requestDto, bool allowLocal)
{
if (HostContext.HasValidAuthSecret(req))
return;
@@ -50,13 +50,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
//ExecuteBasic(req, res, requestDto); //first check if session is authenticated
//if (res.IsClosed) return; //AuthenticateAttribute already closed the request (ie auth failed)
- ValidateUser(req);
+ ValidateUser(req, allowLocal);
}
// TODO: Remove this when all clients have supported the new sescurity
- private readonly List<string> _updatedClients = new List<string>(){"Dashboard"};
+ private readonly List<string> _updatedClients = new List<string>() { "Dashboard", "Chromecast" };
- private void ValidateUser(IRequest req)
+ private void ValidateUser(IRequest req, bool allowLocal)
{
//This code is executed before the service
var auth = AuthorizationContext.GetAuthorizationInfo(req);
@@ -65,7 +65,10 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
|| _config.Configuration.EnableTokenAuthentication
|| _updatedClients.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- SessionManager.ValidateSecurityToken(auth.Token);
+ if (!allowLocal || !req.IsLocal)
+ {
+ SessionManager.ValidateSecurityToken(auth.Token);
+ }
}
var user = string.IsNullOrWhiteSpace(auth.UserId)
@@ -96,35 +99,6 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security
}
}
- private void ExecuteBasic(IRequest req, IResponse res, object requestDto)
- {
- if (AuthenticateService.AuthProviders == null)
- throw new InvalidOperationException(
- "The AuthService must be initialized by calling AuthService.Init to use an authenticate attribute");
-
- var matchingOAuthConfigs = AuthenticateService.AuthProviders.Where(x =>
- this.Provider.IsNullOrEmpty()
- || x.Provider == this.Provider).ToList();
-
- if (matchingOAuthConfigs.Count == 0)
- {
- res.WriteError(req, requestDto, "No OAuth Configs found matching {0} provider"
- .Fmt(this.Provider ?? "any"));
- res.EndRequest();
- }
-
- matchingOAuthConfigs.OfType<IAuthWithRequest>()
- .Each(x => x.PreAuthenticate(req, res));
-
- var session = req.GetSession();
- if (session == null || !matchingOAuthConfigs.Any(x => session.IsAuthorized(x.Provider)))
- {
- if (this.DoHtmlRedirectIfConfigured(req, res, true)) return;
-
- AuthProvider.HandleFailedAuth(matchingOAuthConfigs[0], session, req, res);
- }
- }
-
protected bool DoHtmlRedirectIfConfigured(IRequest req, IResponse res, bool includeRedirectParam = false)
{
var htmlRedirect = this.HtmlRedirect ?? AuthenticateService.HtmlRedirect;
diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
index 477aa3878..f2fae9e90 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpListener.cs
@@ -3,7 +3,6 @@ using MediaBrowser.Model.Logging;
using ServiceStack;
using ServiceStack.Web;
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -15,20 +14,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
public class WebSocketSharpListener : IHttpListener
{
- private readonly ConcurrentDictionary<string, string> _localEndPoints = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private WebSocketSharp.Net.HttpListener _listener;
private readonly AutoResetEvent _listenForNextRequest = new AutoResetEvent(false);
private readonly ILogger _logger;
+ private readonly Action<string> _endpointListener;
- public WebSocketSharpListener(ILogger logger)
+ public WebSocketSharpListener(ILogger logger, Action<string> endpointListener)
{
_logger = logger;
- }
-
- public IEnumerable<string> LocalEndPoints
- {
- get { return _localEndPoints.Keys.ToList(); }
+ _endpointListener = endpointListener;
}
public Action<Exception, IRequest> ErrorHandler { get; set; }
@@ -170,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp
{
var address = endpoint.ToString();
- _localEndPoints.GetOrAdd(address, address);
+ _endpointListener(address);
}
LogRequest(_logger, request);
diff --git a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
index f1112ae0b..28fc094f7 100644
--- a/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
+++ b/MediaBrowser.Server.Implementations/HttpServer/StreamWriter.cs
@@ -38,7 +38,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer
public bool Throttle { get; set; }
public long ThrottleLimit { get; set; }
-
+ public long MinThrottlePosition;
+
/// <summary>
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
/// </summary>
@@ -84,7 +85,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
{
responseStream = new ThrottledStream(responseStream, ThrottleLimit)
{
- MinThrottlePosition = ThrottleLimit * 180
+ MinThrottlePosition = MinThrottlePosition
};
}
var task = WriteToAsync(responseStream);
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
index 91796d5dc..84f1d5aaa 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "\u0645\u0648\u0633\u064a\u0642\u0649 \u0627\u0644\u0641\u064a\u062f\u064a\u0648",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
index 1440a079c..8bec53c5f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Music Videos",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
index e9e733300..f2219933f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Hudebn\u00ed videa",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
index 4703d6b9f..7d7492e64 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Musik Videoer",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
index e671c7da0..dfa4fd59e 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Musikvideos",
"BirthPlaceValue": "Geburtsort: {0}",
"DeathDateValue": "Gestorben: {0}",
- "BirthDateValue": "Geboren: {0}"
+ "BirthDateValue": "Geboren: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
index f961db055..3d57ae21f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "\u039c\u03bf\u03c5\u03c3\u03b9\u03ba\u03ac \u03b2\u03af\u03bd\u03c4\u03b5\u03bf",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
index e8525157d..9db725ec7 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Music Videos",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
index dd6e416e1..b740506ae 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Music Videos",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
index c05f42914..3d736ba36 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Videos Musicales",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
index 9db75b4bc..27930a13a 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Videos Musicales",
"BirthPlaceValue": "Lugar de nacimiento: {0}",
"DeathDateValue": "Fallcimiento: {0}",
- "BirthDateValue": "Nacimiento: {0}"
+ "BirthDateValue": "Nacimiento: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
index 7b1feb6b3..ca08980ab 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Videos musicales",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
index e81dc5775..aaff70b69 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "\u05e7\u05dc\u05d9\u05e4\u05d9\u05dd",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
index 50cc701cf..5ded6e80b 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Video Musicali",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
index c8ce64b83..bdc184a37 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json
@@ -383,58 +383,67 @@
"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",
- "ButtonRemove": "Remove",
- "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}"
+ "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",
+ "ButtonRemove": "Remove",
+ "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)"
}
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
index 0e07e2f02..8572c0b6b 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json
@@ -132,14 +132,14 @@
"HeaderRatingsDownloads": "\u0411\u0430\u0493\u0430\u043b\u0430\u0443 \/ \u0416\u04af\u043a\u0442\u0435\u0443\u043b\u0435\u0440",
"HeaderConfirmProfileDeletion": "\u041f\u0440\u043e\u0444\u0430\u0439\u043b \u0436\u043e\u044e\u0434\u044b \u0440\u0430\u0441\u0442\u0430\u0443",
"MessageConfirmProfileDeletion": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0434\u044b \u0436\u043e\u044e \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?",
- "HeaderSelectServerCachePath": "Server Cache \u049b\u0430\u043b\u0442\u0430\u0441\u044b \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
- "HeaderSelectTranscodingPath": "Transcoding Temporary \u049b\u0430\u043b\u0442\u0430\u0441\u044b \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
- "HeaderSelectImagesByNamePath": "Images By Name \u049b\u0430\u043b\u0442\u0430\u0441\u044b \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
- "HeaderSelectMetadataPath": "Metadata \u049b\u0430\u043b\u0442\u0430\u0441\u044b \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
- "HeaderSelectServerCachePathHelp": "Server cache \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
- "HeaderSelectTranscodingPathHelp": "Transcoding temporary \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
- "HeaderSelectImagesByNamePathHelp": "Items by name \u049b\u0430\u043b\u0442\u0430\u0441\u044b \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
- "HeaderSelectMetadataPathHelp": "Metadata \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u043d \u0441\u0430\u049b\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
+ "HeaderSelectServerCachePath": "\u0421\u0435\u0440\u0432\u0435\u0440 \u043a\u0435\u0448\u0456\u043d\u0456\u04a3 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
+ "HeaderSelectTranscodingPath": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u0434\u044b\u04a3 \u0443\u0430\u049b\u044b\u0442\u0448\u0430 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u0435\u044b\u04a3 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
+ "HeaderSelectImagesByNamePath": "\u0410\u0442\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
+ "HeaderSelectMetadataPath": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443",
+ "HeaderSelectServerCachePathHelp": "\u0421\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u043a\u0435\u0448 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
+ "HeaderSelectTranscodingPathHelp": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u0434\u044b\u04a3 \u0443\u0430\u049b\u044b\u0442\u0448\u0430 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u043d \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
+ "HeaderSelectImagesByNamePathHelp": "\u0410\u0442\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
+ "HeaderSelectMetadataPathHelp": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0441\u0430\u049b\u0442\u0430\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
"HeaderSelectChannelDownloadPath": "\u0410\u0440\u043d\u0430 \u0436\u04af\u043a\u0442\u0435\u0443 \u0436\u043e\u043b\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u04a3\u044b\u0437",
"HeaderSelectChannelDownloadPathHelp": "\u0410\u0440\u043d\u0430 \u043a\u0435\u0448\u0456 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b\u043d \u0441\u0430\u049b\u0442\u0430\u043f \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u0436\u043e\u043b\u0434\u044b \u0448\u043e\u043b\u044b\u04a3\u044b\u0437 \u043d\u0435\u043c\u0435\u0441\u0435 \u0435\u043d\u0433\u0456\u0437\u0456\u04a3\u0456\u0437. \u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430 \u0436\u0430\u0437\u0443 \u04af\u0448\u0456\u043d \u049b\u043e\u043b \u0436\u0435\u0442\u0456\u043c\u0434\u0456 \u0431\u043e\u043b\u0443\u044b \u049b\u0430\u0436\u0435\u0442.",
"OptionNewCollection": "\u0416\u0430\u04a3\u0430...",
@@ -275,7 +275,7 @@
"OptionGenres": "\u0416\u0430\u043d\u0440\u043b\u0430\u0440",
"OptionParentalRating": "\u0416\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442",
"OptionPeople": "\u0410\u0434\u0430\u043c\u0434\u0430\u0440",
- "OptionRuntime": "\u041e\u0440\u044b\u043d\u0434\u0430\u0443 \u0443\u0430\u049b\u044b\u0442\u044b",
+ "OptionRuntime": "\u04b0\u0437\u0430\u049b\u0442\u044b\u0493\u044b",
"OptionProductionLocations": "\u04e8\u043d\u0434\u0456\u0440\u0443 \u043e\u0440\u044b\u043d\u0434\u0430\u0440\u044b",
"OptionBirthLocation": "\u0422\u0443\u0493\u0430\u043d \u043e\u0440\u043d\u044b",
"LabelAllChannels": "\u0411\u0430\u0440\u043b\u044b\u049b \u0430\u0440\u043d\u0430\u043b\u0430\u0440",
@@ -429,5 +429,14 @@
"TabMusicVideos": "\u0411\u0435\u0439\u043d\u0435\u043a\u043b\u0438\u043f\u0442\u0435\u0440",
"BirthPlaceValue": "\u0422\u0443\u0493\u0430\u043d \u043e\u0440\u043d\u044b: {0}",
"DeathDateValue": "\u04e8\u043b\u0433\u0435\u043d\u0456: {0}",
- "BirthDateValue": "\u0422\u0443\u0493\u0430\u043d\u044b: {0}"
+ "BirthDateValue": "\u0422\u0443\u0493\u0430\u043d\u044b: {0}",
+ "HeaderLatestReviews": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u043f\u0456\u043a\u0456\u0440\u043b\u0435\u0440",
+ "HeaderPluginInstallation": "\u041f\u043b\u0430\u0433\u0438\u043d \u043e\u0440\u043d\u0430\u0442\u044b\u043c\u044b",
+ "MessageAlreadyInstalled": "\u041e\u0441\u044b \u043d\u04b1\u0441\u049b\u0430 \u0431\u04b1\u0440\u044b\u043d\u043d\u0430\u043d \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d.",
+ "ValueReviewCount": "{0} \u043f\u0456\u043a\u0456\u0440",
+ "MessageYouHaveVersionInstalled": "\u049a\u0430\u0437\u0456\u0440 {0} \u043e\u0440\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d",
+ "MessageTrialExpired": "\u041e\u0441\u044b \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u043a \u04af\u0448\u0456\u043d \u0442\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443 \u043a\u0435\u0437\u0435\u04a3\u0456\u043d\u0456\u04a3 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 \u04e9\u0442\u0442\u0456",
+ "MessageTrialWillExpireIn": "\u041e\u0441\u044b \u043c\u04af\u043c\u043a\u0456\u043d\u0434\u0456\u043a \u04af\u0448\u0456\u043d \u0442\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443 \u043a\u0435\u0437\u0435\u04a3\u0456\u043d\u0456\u04a3 \u043c\u0435\u0440\u0437\u0456\u043c\u0456 {0} \u043a\u04af\u043d\u0434\u0435 \u04e9\u0442\u0435\u0434\u0456",
+ "MessageInstallPluginFromApp": "This plugin must be installed from with in the app you intend to use it in.",
+ "ValuePriceUSD": "\u0411\u0430\u0493\u0430\u0441\u044b: {0} USD"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
index b6d5e50e5..6aff55b44 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Music Videos",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
index 024009e03..13a031937 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Musikk-videoer",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
index 6b722885a..912aabe85 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Music Videos",
"BirthPlaceValue": "Geboorte plaats: {0})",
"DeathDateValue": "Overleden: {0}",
- "BirthDateValue": "Geboren: {0}"
+ "BirthDateValue": "Geboren: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
index b9238b554..be23009ba 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Teledyski",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
index db6012513..e4b0dee4c 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json
@@ -58,14 +58,14 @@
"ButtonMute": "Mudo",
"ButtonUnmute": "Remover Mudo",
"ButtonStop": "Parar",
- "ButtonNextTrack": "Faixa seguinte",
+ "ButtonNextTrack": "Pr\u00f3xima Faixa",
"ButtonPause": "Pausar",
"ButtonPlay": "Reproduzir",
"ButtonEdit": "Editar",
"ButtonQueue": "Adicionar \u00e0 fila",
"ButtonPlayTrailer": "Reproduzir trailer",
"ButtonPlaylist": "Lista de reprodu\u00e7\u00e3o",
- "ButtonPreviousTrack": "Faixa anterior",
+ "ButtonPreviousTrack": "Faixa Anterior",
"LabelEnabled": "Ativada",
"LabelDisabled": "Desativada",
"ButtonMoreInformation": "Mais informa\u00e7\u00f5es",
@@ -429,5 +429,14 @@
"TabMusicVideos": "V\u00eddeos Musicais",
"BirthPlaceValue": "Local de nascimento: {0}",
"DeathDateValue": "Morte: {0}",
- "BirthDateValue": "Nascimento: {0}"
+ "BirthDateValue": "Nascimento: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
index 6f3146bfd..00ed7f622 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Videos Musicais",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
index b00872075..76e572669 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json
@@ -137,7 +137,7 @@
"HeaderSelectImagesByNamePath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u0434\u043b\u044f \u043f\u0430\u043f\u043a\u0438 Images By Name",
"HeaderSelectMetadataPath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u0434\u043b\u044f \u043f\u0430\u043f\u043a\u0438 Metadata",
"HeaderSelectServerCachePathHelp": "\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0438\u043b\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0443\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432 server cache. \u041f\u0430\u043f\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.",
- "HeaderSelectTranscodingPathHelp": "\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0438\u043b\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0443\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432 transcoding temporary. \u041f\u0430\u043f\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.",
+ "HeaderSelectTranscodingPathHelp": "\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0438\u043b\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0443\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438. \u041f\u0430\u043f\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.",
"HeaderSelectImagesByNamePathHelp": "\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0438\u043b\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 items by name. \u041f\u0430\u043f\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.",
"HeaderSelectMetadataPathHelp": "\u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 \u0438\u043b\u0438 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 metadata. \u041f\u0430\u043f\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438.",
"HeaderSelectChannelDownloadPath": "\u0412\u044b\u0431\u043e\u0440 \u043f\u0443\u0442\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043a\u0430\u043d\u0430\u043b\u043e\u0432",
@@ -288,7 +288,7 @@
"HeaderAlert": "\u041e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435",
"MessagePleaseRestart": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.",
"ButtonRestart": "\u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c",
- "MessagePleaseRefreshPage": "\u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.",
+ "MessagePleaseRefreshPage": "\u0410\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.",
"ButtonHide": "\u0421\u043a\u0440\u044b\u0442\u044c",
"MessageSettingsSaved": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b.",
"ButtonSignOut": "\u0412\u044b\u0439\u0442\u0438",
@@ -429,5 +429,14 @@
"TabMusicVideos": "\u041a\u043b\u0438\u043f\u044b",
"BirthPlaceValue": "\u041c\u0435\u0441\u0442\u043e \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f: {0}",
"DeathDateValue": "\u041a\u043e\u043d\u0447\u0438\u043d\u0430: {0}",
- "BirthDateValue": "\u0420\u043e\u0436\u0434\u0435\u043d\u0438\u0435: {0}"
+ "BirthDateValue": "\u0420\u043e\u0436\u0434\u0435\u043d\u0438\u0435: {0}",
+ "HeaderLatestReviews": "\u041d\u043e\u0432\u0438\u043d\u043a\u0438 \u043e\u0442\u0437\u044b\u0432\u043e\u0432",
+ "HeaderPluginInstallation": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430",
+ "MessageAlreadyInstalled": "\u0414\u0430\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430.",
+ "ValueReviewCount": "\u041e\u0442\u0437\u044b\u0432\u043e\u0432: {0}",
+ "MessageYouHaveVersionInstalled": "\u0412 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f {0}.",
+ "MessageTrialExpired": "\u041f\u0440\u043e\u0431\u043d\u044b\u0439 \u043f\u0435\u0440\u0438\u043e\u0434 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0441\u0442\u0451\u043a",
+ "MessageTrialWillExpireIn": "\u041f\u0440\u043e\u0431\u043d\u044b\u0439 \u043f\u0435\u0440\u0438\u043e\u0434 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0441\u0442\u0435\u0447\u0451\u0442 \u0447\u0435\u0440\u0435\u0437 {0} \u0434\u043d\u0435\u0439",
+ "MessageInstallPluginFromApp": "\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.",
+ "ValuePriceUSD": "\u0426\u0435\u043d\u0430: {0} USD"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
index 50d24dae5..f6c2313e5 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Musikvideor",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
index 9232c2fdd..c6c2b4491 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Klipler",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
index b62b24367..b63fb262f 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "C\u00e1c video \u00e2m nh\u1ea1c",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
index dc4e7eb84..1b7217efb 100644
--- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json
@@ -429,5 +429,14 @@
"TabMusicVideos": "Music Videos",
"BirthPlaceValue": "Birth place: {0}",
"DeathDateValue": "Died: {0}",
- "BirthDateValue": "Born: {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)"
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ar.json b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
index bb05037f9..5d7ebaffb 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ar.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ar.json
@@ -192,15 +192,25 @@
"TabUpcoming": "\u0627\u0644\u0642\u0627\u062f\u0645",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "\u0627\u0644\u0645\u0633\u0644\u0633\u0644\u0627\u062a",
+ "HeaderInstall": "Install",
"TabEpisodes": "\u0627\u0644\u062d\u0644\u0642\u0627\u062a",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "\u0627\u0646\u0648\u0627\u0639",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "\u0627\u0644\u0646\u0627\u0633",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "\u0627\u0644\u0634\u0628\u0643\u0627\u062a",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "\u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u064a\u0646",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "\u0641\u0644\u062a\u0631\u0627\u062a:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "\u0641\u0644\u062a\u0631",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "\u0627\u0644\u0645\u0641\u0636\u0644\u0627\u062a",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "\u0645\u062d\u0628\u0628",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "\u0645\u0643\u0631\u0648\u0647",
"OptionActors": "\u0627\u0644\u0645\u0645\u062b\u0644\u0648\u0646",
"OptionGuestStars": "\u0636\u064a\u0648\u0641",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ca.json b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
index 36d831887..8b72f1dc2 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ca.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ca.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Upcoming",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodes",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "People",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Networks",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Users",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favorites",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Actors",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/da.json b/MediaBrowser.Server.Implementations/Localization/Server/da.json
index 6d3e9bc04..87fc9288f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/da.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/da.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Kommende",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episoder",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genre",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Personer",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Netv\u00e6rk",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Brugere",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtre:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoritter",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Skuespillere",
"OptionGuestStars": "G\u00e6ste Stjerner",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/de.json b/MediaBrowser.Server.Implementations/Localization/Server/de.json
index 907c466d0..361bd42c8 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/de.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/de.json
@@ -158,7 +158,7 @@
"LabelNewPasswordConfirm": "Neues Passwort wiederhohlen:",
"OptionMakeOneTimeDonation": "Mache eine einmalige Spende",
"HeaderCreatePassword": "Erstelle Passwort",
- "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.",
+ "OptionOneTimeDescription": "Das ist eine zus\u00e4tzliche Spende an das Team, um deine Unterst\u00fctzung zu zeigen. Dies bringt keine zus\u00e4tzlichen Vorteile.",
"LabelCurrentPassword": "Aktuelles Passwort:",
"OptionLifeTimeSupporterClubMembership": "Lebensl\u00e4ngliche Unterst\u00fctzer Club Mitgliedschaft",
"LabelMaxParentalRating": "H\u00f6chste erlaubte elterlich Bewertung:",
@@ -184,23 +184,33 @@
"MessageNothingHere": "Nichts hier.",
"OptionWriter": "Drehbuchautor",
"MessagePleaseEnsureInternetMetadata": "Bitte sicherstellen, dass das Herunterladen von Internet Metadaten aktiviert ist.",
- "LabelAirDays": "Air days:",
+ "LabelAirDays": "Ausstrahlungstage:",
"TabSuggested": "Vorgeschlagen",
- "LabelAirTime": "Air time:",
+ "LabelAirTime": "Ausstrahlungszeit:",
"TabLatest": "Neueste",
- "HeaderMediaInfo": "Media Info",
+ "HeaderMediaInfo": "Medieninformation",
"TabUpcoming": "Bevorstehend",
- "HeaderPhotoInfo": "Photo Info",
+ "HeaderPhotoInfo": "Fotoinformation",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episoden",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Personen",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Sendergruppen",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Benutzer",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filter:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoriten",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Darsteller",
"OptionGuestStars": "Gaststar",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/el.json b/MediaBrowser.Server.Implementations/Localization/Server/el.json
index 2923d3a9f..a7ab23633 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/el.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/el.json
@@ -192,15 +192,25 @@
"TabUpcoming": "\u0395\u03c0\u03b5\u03c1\u03c7\u03cc\u03bc\u03b5\u03bd\u03b7",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
+ "HeaderInstall": "Install",
"TabEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "\u0395\u03af\u03b4\u03b7",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "\u0386\u03bd\u03b8\u03c1\u03c9\u03c0\u03bf\u03b9 ",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "\u0394\u03af\u03ba\u03c4\u03c5\u03b1",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "\u03a7\u03c1\u03ae\u03c3\u03c4\u03b5\u03c2 ",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "\u03a6\u03af\u03bb\u03c4\u03c1\u03b1",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "\u03c6\u03af\u03bb\u03c4\u03c1\u03bf",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "\u0391\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03b1",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "\u03a3\u03c5\u03bc\u03c0\u03b1\u03b8\u03b5\u03af",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "\u0391\u03bd\u03c4\u03b9\u03c0\u03b1\u03b8\u03b5\u03af",
"OptionActors": "\u0397\u03b8\u03bf\u03c0\u03bf\u03b9\u03bf\u03af",
"OptionGuestStars": "\u0393\u03ba\u03b5\u03c3\u03c4 \u03c3\u03c4\u03b1\u03c1",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
index 7d328c042..7209c0e62 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Upcoming",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodes",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "People",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Networks",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Users",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favourites",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Actors",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
index 79f5001b8..29c870d39 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Upcoming",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodes",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "People",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Networks",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Users",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favorites",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Actors",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es.json b/MediaBrowser.Server.Implementations/Localization/Server/es.json
index 4b8bb6cc6..a376fbbf1 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Pr\u00f3ximos",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Programas",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodios",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "G\u00e9neros",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Gente",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "redes",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Usuarios",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtros:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtro",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoritos",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Me gusta",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "No me gusta",
"OptionActors": "Actores",
"OptionGuestStars": "Estrellas invitadas",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
index d040bdc23..f6981335d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json
@@ -156,9 +156,9 @@
"LabelNewPassword": "Nueva contrase\u00f1a:",
"HeaderDonationType": "Tipo de Donaci\u00f3n:",
"LabelNewPasswordConfirm": "Confirmaci\u00f3n de contrase\u00f1a nueva:",
- "OptionMakeOneTimeDonation": "Hacer una donaci\u00f3n \u00fanica",
+ "OptionMakeOneTimeDonation": "Hacer una donaci\u00f3n independiente",
"HeaderCreatePassword": "Crear Contrase\u00f1a",
- "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.",
+ "OptionOneTimeDescription": "Esta es una donaci\u00f3n adicional para mostrar tu apoyo al equipo. No tiene ning\u00fan beneficio adicional.",
"LabelCurrentPassword": "Contrase\u00f1a actual:",
"OptionLifeTimeSupporterClubMembership": "Membres\u00eda vitalicia del club de aficionados",
"LabelMaxParentalRating": "M\u00e1xima clasificaci\u00f3n parental permitida:",
@@ -184,23 +184,33 @@
"MessageNothingHere": "Nada aqu\u00ed.",
"OptionWriter": "Escritor",
"MessagePleaseEnsureInternetMetadata": "Por favor aseg\u00farese que la descarga de metadatos de internet esta habilitada.",
- "LabelAirDays": "Air days:",
+ "LabelAirDays": "Se emite los d\u00edas:",
"TabSuggested": "Sugerencias",
- "LabelAirTime": "Air time:",
+ "LabelAirTime": "Duraci\u00f3n:",
"TabLatest": "Recientes",
- "HeaderMediaInfo": "Media Info",
+ "HeaderMediaInfo": "Info del Medio:",
"TabUpcoming": "Por Estrenar",
- "HeaderPhotoInfo": "Photo Info",
+ "HeaderPhotoInfo": "Info de Fotograf\u00eda:",
"TabShows": "Programas",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodios",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "G\u00e9neros",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Personas",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Cadenas",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Usuarios",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtros:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtro",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoritos",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Me gusta",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "No me gusta",
"OptionActors": "Actores",
"OptionGuestStars": "Estrellas Invitadas",
@@ -225,7 +235,7 @@
"OptionAscending": "Ascendente",
"OptionDescending": "Descendente",
"OptionRuntime": "Duraci\u00f3n",
- "OptionReleaseDate": "Release Date",
+ "OptionReleaseDate": "Fecha de Liberaci\u00f3n",
"OptionPlayCount": "N\u00famero de Reproducc.",
"OptionDatePlayed": "Fecha de Reproducci\u00f3n",
"OptionDateAdded": "Fecha de Adici\u00f3n",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fr.json b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
index f0d030f4d..a8ca45785 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/fr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/fr.json
@@ -192,15 +192,25 @@
"TabUpcoming": "\u00c0 venir",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "S\u00e9ries",
+ "HeaderInstall": "Install",
"TabEpisodes": "\u00c9pisodes",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Personnes",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "R\u00e9seaux",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Utilisateurs",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtres:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtre",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoris",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Aim\u00e9s",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Non aim\u00e9s",
"OptionActors": "Acteurs",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/he.json b/MediaBrowser.Server.Implementations/Localization/Server/he.json
index 70b2bfe84..8f828e6ce 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/he.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/he.json
@@ -192,15 +192,25 @@
"TabUpcoming": "\u05d1\u05e7\u05e8\u05d5\u05d1",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "\u05ea\u05d5\u05db\u05e0\u05d9\u05d5\u05ea",
+ "HeaderInstall": "Install",
"TabEpisodes": "\u05e4\u05e8\u05e7\u05d9\u05dd",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "\u05d6\u05d0\u05e0\u05e8\u05d9\u05dd",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "\u05d0\u05e0\u05e9\u05d9\u05dd",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "\u05e8\u05e9\u05ea\u05d5\u05ea",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "\u05de\u05e9\u05ea\u05de\u05e9\u05d9\u05dd",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "\u05de\u05e1\u05e0\u05e0\u05d9\u05dd:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "\u05de\u05e1\u05e0\u05df",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "\u05de\u05d5\u05e2\u05d3\u05e4\u05d9\u05dd",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "\u05e0\u05d1\u05d7\u05e8\u05d9\u05dd",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "\u05dc\u05d0 \u05d0\u05d5\u05d4\u05d1",
"OptionActors": "\u05e9\u05d7\u05e7\u05e0\u05d9\u05dd",
"OptionGuestStars": "\u05e9\u05d7\u05e7\u05df \u05d0\u05d5\u05e8\u05d7",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/it.json b/MediaBrowser.Server.Implementations/Localization/Server/it.json
index a8ffcc2eb..88820c2c1 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/it.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/it.json
@@ -192,15 +192,25 @@
"TabUpcoming": "IN ONDA A BREVE",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Serie",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodi",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Generi",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Attori",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Internet",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Utenti",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtri",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtro",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Preferiti",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Belli",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Brutti",
"OptionActors": "Attori",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/kk.json b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
index bf0fd1212..eb30d69fd 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/kk.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/kk.json
@@ -66,7 +66,7 @@
"LabelEnableAutomaticPortMapping": "\u041f\u043e\u0440\u0442 \u0430\u0432\u0442\u043e\u0441\u0430\u043b\u0493\u0430\u0441\u0442\u044b\u0440\u0443\u044b\u043d \u049b\u043e\u0441\u0443",
"LabelCommunityRating": "\u049a\u0430\u0443\u044b\u043c \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b:",
"LabelEnableAutomaticPortMappingHelp": "UPnP \u049b\u0430\u0448\u044b\u049b\u0442\u0430\u043d \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0443\u0434\u044b \u0436\u0435\u04a3\u0456\u043b\u0434\u0435\u0442\u0443 \u04af\u0448\u0456\u043d \u0440\u043e\u0443\u0442\u0435\u0440\u0434\u0456 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043b\u0430\u0443\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0435\u0434\u0456. \u0411\u04b1\u043b \u043a\u0435\u0439\u0431\u0456\u0440 \u0440\u043e\u0443\u0442\u0435\u0440 \u04b1\u043b\u0433\u0456\u043b\u0435\u0440\u0456\u043c\u0435\u043d \u0436\u04b1\u043c\u044b\u0441 \u0456\u0441\u0442\u0435\u043c\u0435\u0439\u0442\u0456\u043d\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.",
- "LabelVoteCount": "\u0414\u0430\u0443\u044b\u0441 \u0441\u0430\u043d\u044b:",
+ "LabelVoteCount": "\u0414\u0430\u0443\u044b\u0441 \u0435\u0441\u0435\u0431\u0456:",
"ButtonOk": "\u0416\u0430\u0440\u0430\u0439\u0434\u044b",
"LabelMetascore": "Metascore \u0431\u0430\u0493\u0430\u043b\u0430\u0443\u044b:",
"ButtonCancel": "\u0411\u043e\u043b\u0434\u044b\u0440\u043c\u0430\u0443",
@@ -96,7 +96,7 @@
"LabelDownloadInternetMetadata": "\u0421\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435 \u043c\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0456 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443",
"LabelAirTime:": "\u042d\u0444\u0438\u0440 \u0443\u0430\u049b\u044b\u0442\u044b",
"LabelDownloadInternetMetadataHelp": "\u0422\u043e\u043b\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043b\u0456\u043c\u0434\u0435\u0440\u0434\u0456 \u049b\u043e\u0441\u0443 \u04af\u0448\u0456\u043d Media Browser \u0442\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u0442\u0443\u0440\u0430\u043b\u044b \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0442\u0435\u0440\u0434\u0456 \u0436\u04af\u043a\u0442\u0435\u0443\u0456 \u043c\u04af\u043c\u043a\u0456\u043d.",
- "LabelRuntimeMinutes": "\u041e\u0440\u044b\u043d\u0434\u0430\u043b\u0443 \u0443\u0430\u049b\u044b\u0442\u044b, \u043c\u0438\u043d:",
+ "LabelRuntimeMinutes": "\u04b0\u0437\u0430\u049b\u0442\u044b\u0493\u044b, \u043c\u0438\u043d:",
"TabPreferences": "\u0422\u0435\u04a3\u0448\u0435\u043b\u0456\u043c\u0434\u0435\u0440",
"LabelParentalRating": "\u0416\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442\u044b:",
"TabPassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437",
@@ -156,9 +156,9 @@
"LabelNewPassword": "\u0416\u0430\u04a3\u0430 \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437",
"HeaderDonationType": "\u049a\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0434\u044b\u049b \u0442\u04af\u0440\u0456:",
"LabelNewPasswordConfirm": "\u0416\u0430\u04a3\u0430 \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u0440\u0430\u0441\u0442\u0430\u0443:",
- "OptionMakeOneTimeDonation": "\u0411\u0456\u0440 \u0440\u0435\u0442 \u049b\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0434\u044b\u049b \u0436\u0430\u0441\u0430\u0443",
+ "OptionMakeOneTimeDonation": "\u0411\u04e9\u043b\u0435\u043a \u049b\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0434\u044b\u049b \u0436\u0430\u0441\u0430\u0443",
"HeaderCreatePassword": "\u049a\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437\u0434\u0456 \u0436\u0430\u0441\u0430\u0443",
- "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.",
+ "OptionOneTimeDescription": "\u0411\u04b1\u043b \u049b\u043e\u043b\u0434\u0430\u0443\u044b\u04a3\u044b\u0437\u0434\u044b \u043a\u04e9\u0440\u0441\u0435\u0442\u0443 \u04af\u0448\u0456\u043d \u0442\u043e\u043f\u049b\u0430 \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u049b\u0430\u0439\u044b\u0440\u043c\u0430\u043b\u0434\u044b\u049b. \u0415\u0448\u049b\u0430\u043d\u0434\u0430\u0439 \u049b\u043e\u0441\u044b\u043c\u0448\u0430 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u0440 \u0431\u043e\u043b\u043c\u0430\u0439\u0434\u044b.",
"LabelCurrentPassword": "\u0410\u0493\u044b\u043c\u0434\u0430\u0493\u044b \u049b\u04b1\u043f\u0438\u044f \u0441\u04e9\u0437:",
"OptionLifeTimeSupporterClubMembership": "\u049a\u043e\u043b\u0434\u0430\u0443\u0448\u044b \u043a\u043b\u0443\u0431\u044b\u043d\u044b\u04a3 \u0493\u04b1\u043c\u044b\u0440\u043b\u044b\u049b \u043c\u04af\u0448\u0435\u043b\u0456\u0433\u0456",
"LabelMaxParentalRating": "\u0420\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0456\u043b\u0433\u0435\u043d \u0435\u04a3 \u0436\u043e\u0493\u0430\u0440\u044b \u0436\u0430\u0441\u0442\u0430\u0441 \u0441\u0430\u043d\u0430\u0442\u044b:",
@@ -184,23 +184,33 @@
"MessageNothingHere": "\u041e\u0441\u044b\u043d\u0434\u0430 \u0435\u0448\u0442\u0435\u043c\u0435 \u0436\u043e\u049b.",
"OptionWriter": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439\u0448\u0456",
"MessagePleaseEnsureInternetMetadata": "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0442\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0456 \u0436\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u0443\u044b \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d\u044b\u043d \u0442\u0435\u043a\u0441\u0435\u0440\u0456\u04a3\u0456\u0437.",
- "LabelAirDays": "Air days:",
+ "LabelAirDays": "\u042d\u0444\u0438\u0440 \u043a\u04af\u043d\u0434\u0435\u0440\u0456:",
"TabSuggested": "\u04b0\u0441\u044b\u043d\u044b\u043b\u0493\u0430\u043d",
- "LabelAirTime": "Air time:",
+ "LabelAirTime": "\u042d\u0444\u0438\u0440 \u0443\u0430\u049b\u044b\u0442\u044b:",
"TabLatest": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456",
- "HeaderMediaInfo": "Media Info",
+ "HeaderMediaInfo": "\u0422\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0456",
"TabUpcoming": "\u041a\u04af\u0442\u0456\u043b\u0433\u0435\u043d",
- "HeaderPhotoInfo": "Photo Info",
+ "HeaderPhotoInfo": "\u0424\u043e\u0442\u043e\u0441\u0443\u0440\u0435\u0442 \u043c\u04d9\u043b\u0456\u043c\u0435\u0442\u0456",
"TabShows": "\u041a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440",
+ "HeaderInstall": "\u041e\u0440\u043d\u0430\u0442\u0443",
"TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u0442\u0430\u0440",
+ "LabelSelectVersionToInstall": "\u041e\u0440\u043d\u0430\u0442\u044b\u043c \u043d\u04b1\u0441\u049b\u0430\u0441\u044b\u043d \u0442\u0430\u04a3\u0434\u0430\u0443:",
"TabGenres": "\u0416\u0430\u043d\u0440\u043b\u0430\u0440",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "\u0410\u0434\u0430\u043c\u0434\u0430\u0440",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "\u0422\u0414 \u0436\u0435\u043b\u0456\u043b\u0435\u0440\u0456",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440",
+ "HeaderReviews": "\u041f\u0456\u043a\u0456\u0440\u043b\u0435\u0440",
"HeaderFilters": "\u0421\u04af\u0437\u0433\u0456\u043b\u0435\u0440:",
+ "HeaderDeveloperInfo": "\u0416\u0430\u0441\u0430\u049b\u0442\u0430\u0443\u0448\u044b \u0442\u0443\u0440\u0430\u043b\u044b",
"ButtonFilter": "\u0421\u04af\u0437\u0443",
+ "HeaderRevisionHistory": "\u04e8\u0437\u0433\u0435\u0440\u0456\u0441\u0442\u0435\u0440 \u0442\u0430\u0440\u0438\u0445\u044b",
"OptionFavorite": "\u0422\u0430\u04a3\u0434\u0430\u0443\u043b\u044b\u043b\u0430\u0440",
+ "ButtonViewWebsite": "\u0492\u0430\u043b\u0430\u043c\u0442\u043e\u0440 \u0441\u0430\u0439\u0442\u044b\u043d \u049b\u0430\u0440\u0430\u0443",
"OptionLikes": "\u04b0\u043d\u0430\u0442\u0443\u043b\u0430\u0440",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "\u04b0\u043d\u0430\u0442\u043f\u0430\u0443\u043b\u0430\u0440",
"OptionActors": "\u0410\u043a\u0442\u0435\u0440\u043b\u0435\u0440",
"OptionGuestStars": "\u0428\u0430\u049b\u044b\u0440\u044b\u043b\u0493\u0430\u043d \u0430\u043a\u0442\u0435\u0440\u043b\u0435\u0440",
@@ -224,9 +234,9 @@
"OptionUnplayed": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u043c\u0430\u0493\u0430\u043d",
"OptionAscending": "\u0410\u0440\u0442\u0443\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430",
"OptionDescending": "\u041a\u0435\u043c\u0443\u0456 \u0431\u043e\u0439\u044b\u043d\u0448\u0430",
- "OptionRuntime": "\u041e\u0440\u044b\u043d\u0434\u0430\u0443 \u0443\u0430\u049b\u044b\u0442\u044b",
+ "OptionRuntime": "\u04b0\u0437\u0430\u049b\u0442\u044b\u0493\u044b",
"OptionReleaseDate": "\u0428\u044b\u0493\u0430\u0440\u0443 \u043a\u04af\u043d-\u0430\u0439\u044b",
- "OptionPlayCount": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0441\u0430\u043d\u044b",
+ "OptionPlayCount": "\u041e\u0439\u043d\u0430\u0442\u0443 \u0435\u0441\u0435\u0431\u0456",
"OptionDatePlayed": "\u041e\u0439\u043d\u0430\u0442\u044b\u043b\u0493\u0430\u043d \u043a\u04af\u043d-\u0430\u0439\u044b",
"OptionDateAdded": "\u04ae\u0441\u0442\u0435\u043b\u0433\u0435\u043d \u043a\u04af\u043d-\u0430\u0439\u044b",
"OptionAlbumArtist": "\u0410\u043b\u044c\u0431\u043e\u043c \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b\u0441\u044b",
@@ -353,11 +363,11 @@
"LabelRunServerAtStartupHelp": "\u0411\u04b1\u043b Windows \u0436\u04b1\u043c\u044b\u0441\u044b\u043d \u0431\u0430\u0441\u0442\u0430\u0493\u0430\u043d\u0434\u0430 \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u0442\u0430\u049b\u0442\u0430\u0434\u0430\u0493\u044b \u0431\u0435\u043b\u0433\u0456\u0448\u0435 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u044b\u043b\u0430\u0434\u044b. Windows \u049b\u044b\u0437\u043c\u0435\u0442\u0456\u043d \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443 \u04af\u0448\u0456\u043d, \u049b\u04b1\u0441\u0431\u0435\u043b\u0433\u0456\u043d\u0456 \u0430\u043b\u044b\u04a3\u044b\u0437 \u0436\u04d9\u043d\u0435 \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0456 Windows \u049a\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440 \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0456 \u0430\u0440\u049b\u044b\u043b\u044b \u043e\u0440\u044b\u043d\u0434\u0430\u04a3\u044b\u0437. \u041d\u0430\u0437\u0430\u0440 \u0430\u0443\u0434\u0430\u0440\u044b\u04a3\u044b\u0437! \u0411\u04b1\u043b \u0435\u043a\u0435\u0443\u0456\u043d \u0441\u043e\u043b \u043c\u0435\u0437\u0433\u0456\u043b\u0434\u0435 \u0431\u0456\u0440\u0433\u0435 \u043e\u0440\u044b\u043d\u0434\u0430\u0443 \u043c\u04af\u043c\u043a\u0456\u043d \u0435\u043c\u0435\u0441, \u0441\u043e\u043d\u044b\u043c\u0435\u043d \u049b\u044b\u0437\u043c\u0435\u0442\u0442\u0456 \u0456\u0441\u043a\u0435 \u049b\u043e\u0441\u0443 \u0430\u043b\u0434\u044b\u043d\u0430\u043d \u0436\u04af\u0439\u0435\u043b\u0456\u043a \u0442\u0430\u049b\u0442\u0430\u0434\u0430\u0493\u044b \u0431\u0435\u043b\u0433\u0456\u0448\u0435\u0434\u0435\u043d \u0448\u044b\u0493\u044b\u04a3\u044b\u0437.",
"ButtonSelectDirectory": "\u049a\u0430\u0442\u0430\u043b\u043e\u0433\u0442\u044b \u0431\u04e9\u043b\u0435\u043a\u0442\u0435\u0443",
"LabelCustomPaths": "\u049a\u0430\u043b\u0430\u0443\u044b\u04a3\u044b\u0437 \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u043e\u043b\u0434\u0430\u0440\u0434\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437. \u04d8\u0434\u0435\u043f\u043a\u0456\u043b\u0435\u0440\u0434\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443 \u04af\u0448\u0456\u043d \u04e9\u0440\u0456\u0441\u0442\u0435\u0440\u0434\u0456 \u0431\u043e\u0441 \u049b\u0430\u043b\u0434\u044b\u0440\u044b\u04a3\u044b\u0437.",
- "LabelCachePath": "Cache \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d\u044b\u04a3 \u0436\u043e\u043b\u044b:",
+ "LabelCachePath": "\u041a\u0435\u0448\u043a\u0435 \u049b\u0430\u0440\u0430\u0439 \u0436\u043e\u043b:",
"LabelCachePathHelp": "\u0421\u0443\u0440\u0435\u0442 \u0441\u0438\u044f\u049b\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u043a\u044d\u0448 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u0430\u0439\u0493\u0430\u0441\u044b\u043c\u0434\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437.",
- "LabelImagesByNamePath": "Images by name \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d\u044b\u04a3 \u0436\u043e\u043b\u044b:",
+ "LabelImagesByNamePath": "\u0410\u0442\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0433\u0435 \u049b\u0430\u0440\u0430\u0439 \u0436\u043e\u043b:",
"LabelImagesByNamePathHelp": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0493\u0430\u043d \u0430\u043a\u0442\u0435\u0440, \u043e\u0440\u044b\u043d\u0434\u0430\u0443\u0448\u044b, \u0436\u0430\u043d\u0440, \u0436\u04d9\u043d\u0435 \u0441\u0442\u0443\u0434\u0438\u044f \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u0430\u0439\u0493\u0430\u0441\u044b\u043c\u0434\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437.",
- "LabelMetadataPath": "Metadata \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d\u044b\u04a3 \u0436\u043e\u043b\u044b:",
+ "LabelMetadataPath": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0433\u0435 \u049b\u0430\u0440\u0430\u0439 \u0436\u043e\u043b:",
"LabelMetadataPathHelp": "\u0416\u04af\u043a\u0442\u0435\u043f \u0430\u043b\u044b\u043d\u0493\u0430\u043d \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u043c\u0435\u043b\u0435\u0440 \u0431\u0435\u043d \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u04af\u0448\u0456\u043d \u0442\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u0430\u0439\u0493\u0430\u0441\u044b\u043c\u0434\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437.",
"LabelTranscodingTempPath": "Transcoding temporary \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d\u044b\u04a3 \u0436\u043e\u043b\u044b:",
"LabelTranscodingTempPathHelp": "\u0411\u04b1\u043b \u049b\u0430\u043b\u0442\u0430 \u049b\u04b1\u0440\u0430\u043c\u044b\u043d\u0434\u0430 \u049b\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443 \u049b\u04b1\u0440\u0430\u043b\u044b \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0430\u0442\u044b\u043d \u0436\u04b1\u043c\u044b\u0441 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b \u0431\u0430\u0440. \u0422\u0435\u04a3\u0448\u0435\u043b\u0433\u0435\u043d \u0436\u043e\u043b\u0434\u044b \u0430\u043d\u044b\u049b\u0442\u0430\u04a3\u044b\u0437, \u043d\u0435\u043c\u0435\u0441\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0456\u04a3 \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u049b\u0430\u043b\u0442\u0430\u0441\u044b \u0456\u0448\u0456\u043d\u0434\u0435\u0433\u0456 \u04d9\u0434\u0435\u043f\u043a\u0456\u0441\u0456\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.",
@@ -937,7 +947,7 @@
"OptionLatestTvRecordings": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u0436\u0430\u0437\u0431\u0430\u043b\u0430\u0440",
"LabelProtocolInfo": "\u041f\u0440\u043e\u0442\u043e\u049b\u043e\u043b \u0430\u049b\u043f\u0430\u0440\u0430\u0442\u044b:",
"LabelProtocolInfoHelp": "\u0411\u04b1\u043b \u043c\u04d9\u043d \u0436\u0430\u0431\u0434\u044b\u049b\u0442\u044b\u04a3 GetProtocolInfo \u0441\u04b1\u0440\u0430\u043d\u044b\u0441\u0442\u0430\u0440\u044b\u043d\u0430 \u0436\u0430\u0443\u0430\u043f \u0431\u0435\u0440\u0433\u0435\u043d\u0434\u0435 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u043b\u0430\u0434\u044b.",
- "TabXbmcMetadata": "Xbmc",
+ "TabXbmcMetadata": "XBMC",
"HeaderXbmcMetadataHelp": "Media Browser \u0431\u0430\u0493\u0434\u0430\u0440\u043b\u0430\u043c\u0430\u0441\u044b Xbmc Nfo \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0442\u0435\u0440\u0456\u043d\u0456\u04a3 \u0436\u04d9\u043d\u0435 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440\u0456\u043d\u0456\u04a3 \u043a\u0456\u0440\u0456\u043a\u0442\u0456\u0440\u043c\u0435 \u049b\u043e\u043b\u0434\u0430\u0443\u044b\u043d \u049b\u0430\u043c\u0442\u0438\u0434\u044b. Xbmc \u043c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0456\u043d \u049b\u043e\u0441\u0443 \u043d\u0435\u043c\u0435\u0441\u0435 \u04e9\u0448\u0456\u0440\u0443 \u04af\u0448\u0456\u043d \u049a\u044b\u0437\u043c\u0435\u0442\u0442\u0435\u0440 \u049b\u043e\u0439\u044b\u043d\u0434\u044b\u0441\u044b\u043d\u0434\u0430\u0493\u044b \u0442\u0430\u0441\u0443\u0448\u044b \u0442\u04af\u0440\u043b\u0435\u0440\u0456\u043d\u0435 \u0430\u0440\u043d\u0430\u043b\u0493\u0430\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440\u0434\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437.",
"LabelXbmcMetadataUser": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043d\u044b\u04a3 \u049b\u0430\u0440\u0430\u0443 \u043a\u04af\u0439\u0456\u043d nfo \u04af\u0448\u0456\u043d \u043c\u044b\u043d\u0430\u0493\u0430\u043d \u049b\u043e\u0441\u0443:",
"LabelXbmcMetadataUserHelp": "\u041a\u04e9\u0440\u0456\u043b\u0433\u0435\u043d \u043a\u04af\u0439\u0434\u0456 Media Browser \u0436\u04d9\u043d\u0435 Xbmc \u0430\u0440\u0430\u0441\u044b\u043d\u0434\u0430 \u04af\u0439\u043b\u0435\u0441\u0442\u0456\u0440\u0456\u043f \u0442\u04b1\u0440\u0443 \u04af\u0448\u0456\u043d \u0431\u04b1\u043d\u044b \u049b\u043e\u0441\u044b\u04a3\u044b\u0437.",
@@ -965,11 +975,11 @@
"OptionList": "\u0422\u0456\u0437\u0456\u043c",
"TabDashboard": "\u0411\u0430\u049b\u044b\u043b\u0430\u0443 \u0442\u0430\u049b\u0442\u0430\u0441\u044b",
"TitleServer": "\u0421\u0435\u0440\u0432\u0435\u0440",
- "LabelCache": "Cache:",
- "LabelLogs": "Logs:",
- "LabelMetadata": "Metadata:",
- "LabelImagesByName": "Images by name:",
- "LabelTranscodingTemporaryFiles": "Transcoding temporary files:",
+ "LabelCache": "\u041a\u0435\u0448:",
+ "LabelLogs": "\u0416\u04b1\u0440\u043d\u0430\u043b\u0434\u0430\u0440:",
+ "LabelMetadata": "\u041c\u0435\u0442\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440:",
+ "LabelImagesByName": "\u0410\u0442\u044b \u0431\u043e\u0439\u044b\u043d\u0448\u0430 \u0441\u0443\u0440\u0435\u0442\u0442\u0435\u0440:",
+ "LabelTranscodingTemporaryFiles": "\u049a\u0430\u0439\u0442\u0430 \u043a\u043e\u0434\u0442\u0430\u0443\u044b\u043d\u044b\u04a3 \u0443\u0430\u049b\u044b\u0442\u0448\u0430 \u0444\u0430\u0439\u043b\u0434\u0430\u0440\u044b:",
"HeaderLatestMusic": "\u0415\u04a3 \u043a\u0435\u0439\u0456\u043d\u0433\u0456 \u043c\u0443\u0437\u044b\u043a\u0430",
"HeaderBranding": "\u0411\u0440\u0435\u043d\u0434\u0438\u04a3\u0433",
"HeaderApiKeys": "API \u043a\u0456\u043b\u0442\u0442\u0435\u0440\u0456",
@@ -1010,7 +1020,7 @@
"TabSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443",
"TitleUsers": "\u041f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u0443\u0448\u044b\u043b\u0430\u0440",
"LabelProtocol": "\u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b:",
- "OptionProtocolHttp": "Http",
+ "OptionProtocolHttp": "HTTP",
"OptionProtocolHls": "Http \u0422\u0456\u043a\u0435\u043b\u0435\u0439 \u0410\u0493\u044b\u043d (HLS)",
"LabelContext": "\u041c\u04d9\u0442\u0456\u043d\u043c\u04d9\u043d:",
"OptionContextStreaming": "\u0410\u0493\u044b\u043d\u043c\u0435\u043d \u0442\u0430\u0441\u044b\u043c\u0430\u043b\u0434\u0430\u0443",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ko.json b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
index 3a322eba7..956e4909a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ko.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ko.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Upcoming",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodes",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "People",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Networks",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Users",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favorites",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Actors",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ms.json b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
index 0180f0060..5311a3875 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ms.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ms.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Upcoming",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episodes",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "People",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Networks",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Users",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favorites",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Actors",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nb.json b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
index 21236b292..5186d9799 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nb.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nb.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Kommer",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Show",
+ "HeaderInstall": "Install",
"TabEpisodes": "Episoder",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Sjanger",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Folk",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Nettverk",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Bruker",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtre",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoritter",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Liker",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Misliker",
"OptionActors": "Skuespiller",
"OptionGuestStars": "Gjeste-opptredelser",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nl.json b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
index 8eda36b99..210531a01 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/nl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/nl.json
@@ -158,7 +158,7 @@
"LabelNewPasswordConfirm": "Bevestig nieuw wachtwoord:",
"OptionMakeOneTimeDonation": "Doe een eenmalige donatie",
"HeaderCreatePassword": "Maak wachtwoord",
- "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.",
+ "OptionOneTimeDescription": "Dit is een extra donatie voor het team om te laten zien dat je ze steunt. Het geeft geen extra voordelen.",
"LabelCurrentPassword": "Huidig wachtwoord",
"OptionLifeTimeSupporterClubMembership": "Levenslang supporters club lidmaatschap",
"LabelMaxParentalRating": "Maximaal toegestane kijkwijzer classificatie:",
@@ -172,35 +172,45 @@
"ButtonDeleteImage": "Verwijder afbeelding",
"LabelOneTimeDonationAmount": "Donatie bedrag:",
"LabelSelectUsers": "Selecteer gebruikers:",
- "OptionActor": "Actor",
+ "OptionActor": "Acteur",
"ButtonUpload": "Uploaden",
- "OptionComposer": "Composer",
+ "OptionComposer": "Componist",
"HeaderUploadNewImage": "Nieuwe afbeelding uploaden",
- "OptionDirector": "Director",
+ "OptionDirector": "Regiseur",
"LabelDropImageHere": "Afbeelding hier neerzetten",
- "OptionGuestStar": "Guest star",
+ "OptionGuestStar": "Gast ster",
"ImageUploadAspectRatioHelp": "1:1 beeldverhouding geadviseerd. Alleen JPG\/PNG.",
- "OptionProducer": "Producer",
+ "OptionProducer": "Producent",
"MessageNothingHere": "Lijst is leeg.",
- "OptionWriter": "Writer",
+ "OptionWriter": "Schrijver",
"MessagePleaseEnsureInternetMetadata": "Zorg ervoor dat het downloaden van metadata van het internet is ingeschakeld.",
- "LabelAirDays": "Air days:",
+ "LabelAirDays": "Uitzend dagen:",
"TabSuggested": "Aanbevolen",
- "LabelAirTime": "Air time:",
+ "LabelAirTime": "Uitzend tijd:",
"TabLatest": "Nieuw",
- "HeaderMediaInfo": "Media Info",
+ "HeaderMediaInfo": "Media informatie",
"TabUpcoming": "Binnenkort",
- "HeaderPhotoInfo": "Photo Info",
+ "HeaderPhotoInfo": "Foto informatie",
"TabShows": "Series",
+ "HeaderInstall": "Install",
"TabEpisodes": "Afleveringen",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genres",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Personen",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "TV-Studio's",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Gebruikers",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favorieten",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Leuk",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Niet leuk",
"OptionActors": "Acteurs",
"OptionGuestStars": "Gast Sterren",
@@ -854,15 +864,15 @@
"LabelDisplayPluginsFor": "Toon Plug-ins voor:",
"PluginTabMediaBrowserClassic": "MB Classic",
"PluginTabMediaBrowserTheater": "MB Theater",
- "LabelEpisodeNamePlain": "Episode name",
- "LabelSeriesNamePlain": "Series name",
+ "LabelEpisodeNamePlain": "Naam aflevering",
+ "LabelSeriesNamePlain": "Naam serie",
"ValueSeriesNamePeriod": "Serie.Naam",
"ValueSeriesNameUnderscore": "Serie_naam",
"ValueEpisodeNamePeriod": "Aflevering.naam",
"ValueEpisodeNameUnderscore": "Aflevering_naam",
- "LabelSeasonNumberPlain": "Season number",
- "LabelEpisodeNumberPlain": "Episode number",
- "LabelEndingEpisodeNumberPlain": "Ending episode number",
+ "LabelSeasonNumberPlain": "nummer seizoen",
+ "LabelEpisodeNumberPlain": "Nummer aflevering",
+ "LabelEndingEpisodeNumberPlain": "Laatste nummer aflevering",
"HeaderTypeText": "Voer tekst in",
"LabelTypeText": "Tekst",
"HeaderSearchForSubtitles": "Zoeken naar Ondertitels",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pl.json b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
index fcd29a463..161f4578c 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pl.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pl.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Upcoming",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Seriale",
+ "HeaderInstall": "Install",
"TabEpisodes": "Odcinki",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Rodzaje",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Osoby",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Sieci",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "U\u017cytkownicy",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtry:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtr",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Ulubione",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Likes",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Dislikes",
"OptionActors": "Aktorzy",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
index fa01486a8..4a8b6d59d 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json
@@ -92,9 +92,9 @@
"LabelSaveLocalMetadata": "Salvar artwork e metadados dentro das pastas da m\u00eddia",
"LabelEndDate": "Data final:",
"LabelSaveLocalMetadataHelp": "Salvar artwork e metadados diretamente nas pastas da m\u00eddia as deixar\u00e1 em um local f\u00e1cil para edit\u00e1-las.",
- "LabelAirDate": "Dias de exibi\u00e7\u00e3o:",
+ "LabelAirDate": "Dias da exibi\u00e7\u00e3o:",
"LabelDownloadInternetMetadata": "Fazer download das imagens e metadados da internet",
- "LabelAirTime:": "Hora da exibi\u00e7\u00e3o:",
+ "LabelAirTime:": "Hor\u00e1rio:",
"LabelDownloadInternetMetadataHelp": "O Media Browser pode fazer download das informa\u00e7\u00f5es de sua m\u00eddia para melhorar a apresenta\u00e7\u00e3o.",
"LabelRuntimeMinutes": "Dura\u00e7\u00e3o (minutos):",
"TabPreferences": "Prefer\u00eancias",
@@ -156,9 +156,9 @@
"LabelNewPassword": "Nova senha:",
"HeaderDonationType": "Tipo de doa\u00e7\u00e3o:",
"LabelNewPasswordConfirm": "Confirmar nova senha:",
- "OptionMakeOneTimeDonation": "Fazer doa\u00e7\u00e3o uma \u00fanica vez",
+ "OptionMakeOneTimeDonation": "Fazer uma doa\u00e7\u00e3o \u00fanica",
"HeaderCreatePassword": "Criar Senha",
- "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.",
+ "OptionOneTimeDescription": "Esta \u00e9 uma doa\u00e7\u00e3o adicional \u00e0 equipe para demonstrar seu apoio. N\u00e3o garante nenhum benef\u00edcio adicional.",
"LabelCurrentPassword": "Senha atual:",
"OptionLifeTimeSupporterClubMembership": "Filia\u00e7\u00e3o vital\u00edcia do clube do colaborador",
"LabelMaxParentalRating": "Classifica\u00e7\u00e3o parental m\u00e1xima permitida:",
@@ -184,23 +184,33 @@
"MessageNothingHere": "Nada aqui.",
"OptionWriter": "Escritor",
"MessagePleaseEnsureInternetMetadata": "Por favor, certifique-se que o download de metadados da internet est\u00e1 habilitado.",
- "LabelAirDays": "Air days:",
+ "LabelAirDays": "Dias da exibi\u00e7\u00e3o:",
"TabSuggested": "Sugeridos",
- "LabelAirTime": "Air time:",
+ "LabelAirTime": "Hor\u00e1rio:",
"TabLatest": "Recentes",
- "HeaderMediaInfo": "Media Info",
+ "HeaderMediaInfo": "Informa\u00e7\u00f5es da M\u00eddia",
"TabUpcoming": "Por Estrear",
- "HeaderPhotoInfo": "Photo Info",
+ "HeaderPhotoInfo": "Informa\u00e7\u00f5es da Foto",
"TabShows": "S\u00e9ries",
+ "HeaderInstall": "Install",
"TabEpisodes": "Epis\u00f3dios",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "G\u00eaneros",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Pessoas",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Redes",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Usu\u00e1rios",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtros:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtro",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoritos",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Gostei",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "N\u00e3o Gostei",
"OptionActors": "Atores",
"OptionGuestStars": "Convidados Especiais",
@@ -288,7 +298,7 @@
"HeaderStatus": "Status",
"OptionContinuing": "Em Exibi\u00e7\u00e3o",
"OptionEnded": "Finalizada",
- "HeaderAirDays": "Dias de Exibi\u00e7\u00e3o",
+ "HeaderAirDays": "Dias da Exibi\u00e7\u00e3o",
"OptionSunday": "Domingo",
"OptionMonday": "Segunda-feira",
"OptionTuesday": "Ter\u00e7a-feira",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
index 359d838d9..2826927cb 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Pr\u00f3ximos",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "S\u00e9ries",
+ "HeaderInstall": "Install",
"TabEpisodes": "Epis\u00f3dios",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "G\u00e9neros Art\u00edsticos",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Pessoas",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "Redes",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Utilizadores",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtros:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtro",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoritos",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Gostos",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "N\u00e3o gostos",
"OptionActors": "Actores",
"OptionGuestStars": "Actores convidados",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ru.json b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
index 2902f716d..7b437805f 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/ru.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/ru.json
@@ -66,7 +66,7 @@
"LabelEnableAutomaticPortMapping": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u043e\u0432",
"LabelCommunityRating": "\u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430:",
"LabelEnableAutomaticPortMappingHelp": "UPnP \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u043e\u0431\u043b\u0435\u0433\u0447\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u044d\u0442\u043e \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432.",
- "LabelVoteCount": "\u0427\u0438\u0441\u043b\u043e \u0433\u043e\u043b\u043e\u0441\u043e\u0432:",
+ "LabelVoteCount": "\u041f\u043e\u0434\u0441\u0447\u0451\u0442 \u0433\u043e\u043b\u043e\u0441\u043e\u0432:",
"ButtonOk": "\u041e\u041a",
"LabelMetascore": "\u041e\u0446\u0435\u043d\u043a\u0430 Metascore:",
"ButtonCancel": "\u041e\u0442\u043c\u0435\u043d\u0430",
@@ -96,7 +96,7 @@
"LabelDownloadInternetMetadata": "\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430",
"LabelAirTime:": "\u0412\u0440\u0435\u043c\u044f \u044d\u0444\u0438\u0440\u0430:",
"LabelDownloadInternetMetadataHelp": "\u0414\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0432 Media Browser.",
- "LabelRuntimeMinutes": "\u0412\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u0435\u043d\u0438\u044f, \u043c\u0438\u043d:",
+ "LabelRuntimeMinutes": "\u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043c\u0438\u043d:",
"TabPreferences": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
"LabelParentalRating": "\u0412\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f:",
"TabPassword": "\u041f\u0430\u0440\u043e\u043b\u044c",
@@ -156,9 +156,9 @@
"LabelNewPassword": "\u041d\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c",
"HeaderDonationType": "\u0422\u0438\u043f \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f:",
"LabelNewPasswordConfirm": "\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f",
- "OptionMakeOneTimeDonation": "\u041e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u043e\u0435 \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435",
+ "OptionMakeOneTimeDonation": "\u041f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e",
"HeaderCreatePassword": "\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c",
- "OptionOneTimeDescription": "This is an additional donation to the team to show your support. It does not have any additional benefits.",
+ "OptionOneTimeDescription": "\u042d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0430\u0448\u0443 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443. \u041d\u0435 \u0434\u0430\u0451\u0442 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432.",
"LabelCurrentPassword": "\u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0430\u0440\u043e\u043b\u044c",
"OptionLifeTimeSupporterClubMembership": "\u041f\u043e\u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0435 \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0432 \u043a\u043b\u0443\u0431\u0435 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u043e\u0432",
"LabelMaxParentalRating": "\u041c\u0430\u043a\u0441. \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d\u043d\u0430\u044f \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f:",
@@ -184,23 +184,33 @@
"MessageNothingHere": "\u0417\u0434\u0435\u0441\u044c \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e.",
"OptionWriter": "\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0441\u0442",
"MessagePleaseEnsureInternetMetadata": "\u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430.",
- "LabelAirDays": "Air days:",
+ "LabelAirDays": "\u0414\u043d\u0438 \u044d\u0444\u0438\u0440\u0430:",
"TabSuggested": "\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435",
- "LabelAirTime": "Air time:",
+ "LabelAirTime": "\u0412\u0440\u0435\u043c\u044f \u044d\u0444\u0438\u0440\u0430:",
"TabLatest": "\u041d\u043e\u0432\u0438\u043d\u043a\u0438",
- "HeaderMediaInfo": "Media Info",
+ "HeaderMediaInfo": "\u0421\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445",
"TabUpcoming": "\u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435",
- "HeaderPhotoInfo": "Photo Info",
+ "HeaderPhotoInfo": "\u0421\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438",
"TabShows": "\u0426\u0438\u043a\u043b\u044b",
+ "HeaderInstall": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430",
"TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u044b",
+ "LabelSelectVersionToInstall": "\u0412\u044b\u0431\u043e\u0440 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438:",
"TabGenres": "\u0416\u0430\u043d\u0440\u044b",
+ "LinkSupporterMembership": "\u041e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e\u043c \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u043e\u0432",
"TabPeople": "\u041b\u044e\u0434\u0438",
+ "MessageSupporterPluginRequiresMembership": "\u0414\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043b\u0430\u0433\u0438\u043d\u0443 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0447\u0435\u0440\u0435\u0437 14 \u0434\u043d\u0435\u0439 \u043f\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0438\u043e\u0434\u0430.",
"TabNetworks": "\u0422\u0435\u043b\u0435\u0441\u0435\u0442\u0438",
+ "MessagePremiumPluginRequiresMembership": "\u0414\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043b\u0430\u0433\u0438\u043d\u0443 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 14 \u0434\u043d\u0435\u0439 \u043f\u0440\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u0435\u0440\u0438\u043e\u0434\u0430.",
"HeaderUsers": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438",
+ "HeaderReviews": "\u041e\u0442\u0437\u044b\u0432\u044b",
"HeaderFilters": "\u0424\u0438\u043b\u044c\u0442\u0440\u044b:",
+ "HeaderDeveloperInfo": "\u0421\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435",
"ButtonFilter": "\u0424\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c",
+ "HeaderRevisionHistory": "\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439",
"OptionFavorite": "\u0418\u0437\u0431\u0440\u0430\u043d\u043d\u044b\u0435",
+ "ButtonViewWebsite": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u0435\u0431\u0441\u0430\u0439\u0442",
"OptionLikes": "\u041d\u0440\u0430\u0432\u0438\u0442\u0441\u044f",
+ "LabelRecurringDonationCanBeCancelledHelp": "\u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u043f\u043e\u0436\u0435\u0440\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432 \u043b\u044e\u0431\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0447\u0435\u0440\u0435\u0437 \u0432\u0430\u0448\u0443 \u0443\u0447\u0451\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c PayPal.",
"OptionDislikes": "\u041d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f",
"OptionActors": "\u0410\u043a\u0442\u0451\u0440\u044b",
"OptionGuestStars": "\u041f\u0440\u0438\u0433\u043b\u0430\u0448\u0451\u043d\u043d\u044b\u0435 \u0430\u043a\u0442\u0451\u0440\u044b",
@@ -226,7 +236,7 @@
"OptionDescending": "\u0423\u0431\u044b\u0432\u0430\u043d\u0438\u0435",
"OptionRuntime": "\u0414\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c",
"OptionReleaseDate": "\u0414\u0430\u0442\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430",
- "OptionPlayCount": "\u0427\u0438\u0441\u043b\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439",
+ "OptionPlayCount": "\u041f\u043e\u0434\u0441\u0447\u0451\u0442 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439",
"OptionDatePlayed": "\u0414\u0430\u0442\u0430 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f",
"OptionDateAdded": "\u0414\u0430\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f",
"OptionAlbumArtist": "\u0410\u043b\u044c\u0431\u043e\u043c. \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c",
@@ -353,13 +363,13 @@
"LabelRunServerAtStartupHelp": "\u0417\u043d\u0430\u0447\u043e\u043a \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u043c \u043b\u043e\u0442\u043a\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0442\u0430\u0440\u0442\u0430 Windows. \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u043b\u0443\u0436\u0431\u0443 Windows, \u0443\u0431\u0435\u0440\u0438\u0442\u0435 \u0433\u0430\u043b\u043e\u0447\u043a\u0443 \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0441\u043b\u0443\u0436\u0431\u0443 \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f Windows. \u041f\u0440\u0438\u043c\u0438\u0442\u0435 \u043a \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044e, \u0447\u0442\u043e \u043e\u043d\u0438 \u043e\u0431\u0430 \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u043e\u043a \u0432 \u043b\u043e\u0442\u043a\u0435 \u0434\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u043b\u0443\u0436\u0431\u044b.",
"ButtonSelectDirectory": "\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u043a\u0430\u0442\u0430\u043b\u043e\u0433",
"LabelCustomPaths": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u043f\u043e \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c. \u041e\u0441\u0442\u0430\u0432\u043b\u044f\u0439\u0442\u0435 \u043f\u043e\u043b\u044f \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445.",
- "LabelCachePath": "\u041f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 Cache:",
+ "LabelCachePath": "\u041f\u0443\u0442\u044c \u043a\u043e \u043a\u0435\u0448\u0443:",
"LabelCachePathHelp": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u043a\u044d\u0448\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432.",
- "LabelImagesByNamePath": "\u041f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 Images by name:",
+ "LabelImagesByNamePath": "\u041f\u0443\u0442\u044c \u043a\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u0430\u043c \u0447\u0435\u0440\u0435\u0437 \u0438\u043c\u044f:",
"LabelImagesByNamePathHelp": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0430\u043a\u0442\u0451\u0440\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u0435\u0439, \u0436\u0430\u043d\u0440\u043e\u0432 \u0438 \u0441\u0442\u0443\u0434\u0438\u0439.",
- "LabelMetadataPath": "\u041f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 Metadata:",
+ "LabelMetadataPath": "\u041f\u0443\u0442\u044c \u043a\u043e \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u043c:",
"LabelMetadataPathHelp": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c\u044b\u0445 \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0439 \u0438 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0445, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043e\u043a.",
- "LabelTranscodingTempPath": "\u041f\u0443\u0442\u044c \u043a \u043f\u0430\u043f\u043a\u0435 Transcoding temporary:",
+ "LabelTranscodingTempPath": "\u041f\u0443\u0442\u044c \u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u0430\u043c \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438:",
"LabelTranscodingTempPathHelp": "\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0444\u0430\u0439\u043b\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0435. \u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c, \u0438\u043b\u0438 \u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043f\u0443\u0441\u0442\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.",
"TabBasics": "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435",
"TabTV": "\u0422\u0412",
@@ -965,11 +975,11 @@
"OptionList": "\u0421\u043f\u0438\u0441\u043e\u043a",
"TabDashboard": "\u0418\u043d\u0444\u043e\u043f\u0430\u043d\u0435\u043b\u044c",
"TitleServer": "\u0421\u0435\u0440\u0432\u0435\u0440",
- "LabelCache": "Cache:",
- "LabelLogs": "Logs:",
- "LabelMetadata": "Metadata:",
- "LabelImagesByName": "Images by name:",
- "LabelTranscodingTemporaryFiles": "Transcoding temporary files:",
+ "LabelCache": "\u041a\u0435\u0448:",
+ "LabelLogs": "\u0416\u0443\u0440\u043d\u0430\u043b\u044b:",
+ "LabelMetadata": "\u041c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435:",
+ "LabelImagesByName": "\u0420\u0438\u0441\u0443\u043d\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u0438\u043c\u044f:",
+ "LabelTranscodingTemporaryFiles": "\u0412\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438:",
"HeaderLatestMusic": "\u041d\u043e\u0432\u0438\u043d\u043a\u0438 \u043c\u0443\u0437\u044b\u043a\u0438",
"HeaderBranding": "\u0411\u0440\u0435\u043d\u0434\u0438\u043d\u0433",
"HeaderApiKeys": "\u041a\u043b\u044e\u0447\u0438 API",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json
index 21eb0c1c9..2ed67ccf0 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/server.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json
@@ -1110,5 +1110,15 @@
"LabelAirDays": "Air days:",
"LabelAirTime": "Air time:",
"HeaderMediaInfo": "Media Info",
- "HeaderPhotoInfo": "Photo Info"
+ "HeaderPhotoInfo": "Photo Info",
+ "HeaderInstall": "Install",
+ "LabelSelectVersionToInstall": "Select version to install:",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
+ "HeaderReviews": "Reviews",
+ "HeaderDeveloperInfo": "Developer Info",
+ "HeaderRevisionHistory": "Revision History",
+ "ButtonViewWebsite": "View website",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account."
}
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/sv.json b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
index 445071cdd..ced6fe1f8 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/sv.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/sv.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Kommande",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Serier",
+ "HeaderInstall": "Install",
"TabEpisodes": "Avsnitt",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "Genrer",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Personer",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "TV-bolag",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Anv\u00e4ndare",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filter:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtrera",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoriter",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Gillar",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Ogillar",
"OptionActors": "Sk\u00e5despelare",
"OptionGuestStars": "G\u00e4startister",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/tr.json b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
index ea2a7e95d..d991debe6 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/tr.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/tr.json
@@ -192,15 +192,25 @@
"TabUpcoming": "Gelecek",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "G\u00f6steriler",
+ "HeaderInstall": "Install",
"TabEpisodes": "B\u00f6l\u00fcmler",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "T\u00fcrler",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "Oyuncular",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "A\u011flar",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "Kullan\u0131c\u0131lar",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filtrelemeler",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filtre",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Favoriler",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Be\u011feniler",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Be\u011fenmeyenler",
"OptionActors": "Akt\u00f6rler",
"OptionGuestStars": "Konuk oylar\u0131",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/vi.json b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
index 3590a5fea..01f7f85c9 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/vi.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/vi.json
@@ -192,15 +192,25 @@
"TabUpcoming": "S\u1eafp di\u1ec5n ra",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "Shows",
+ "HeaderInstall": "Install",
"TabEpisodes": "C\u00e1c t\u1eadp phim",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "C\u00e1c th\u1ec3 lo\u1ea1i",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "M\u1ecdi ng\u01b0\u1eddi",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "C\u00e1c m\u1ea1ng",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "d\u00f9ng",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "Filters:",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "Filter",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "Y\u00eau th\u00edch",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "Th\u00edch",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "Kh\u00f4ng th\u00edch",
"OptionActors": "Di\u1ec5n vi\u00ean",
"OptionGuestStars": "Guest Stars",
diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
index 50a794ec8..0c3ba3c4a 100644
--- a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
+++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json
@@ -192,15 +192,25 @@
"TabUpcoming": "\u5373\u5c07\u767c\u5e03",
"HeaderPhotoInfo": "Photo Info",
"TabShows": "\u7bc0\u76ee",
+ "HeaderInstall": "Install",
"TabEpisodes": "\u55ae\u5143",
+ "LabelSelectVersionToInstall": "Select version to install:",
"TabGenres": "\u985e\u578b",
+ "LinkSupporterMembership": "Learn about the Supporter Membership",
"TabPeople": "\u4eba\u7269",
+ "MessageSupporterPluginRequiresMembership": "This plugin will require an active supporter membership after the 14 day free trial.",
"TabNetworks": "\u7db2\u7d61",
+ "MessagePremiumPluginRequiresMembership": "This plugin will require an active supporter membership in order to purchase after the 14 day free trial.",
"HeaderUsers": "\u7528\u6236",
+ "HeaderReviews": "Reviews",
"HeaderFilters": "\u904e\u6ffe\uff1a",
+ "HeaderDeveloperInfo": "Developer Info",
"ButtonFilter": "\u904e\u6ffe",
+ "HeaderRevisionHistory": "Revision History",
"OptionFavorite": "\u6211\u7684\u6700\u611b",
+ "ButtonViewWebsite": "View website",
"OptionLikes": "\u559c\u6b61",
+ "LabelRecurringDonationCanBeCancelledHelp": "Recurring donations can be cancelled at any time from within your PayPal account.",
"OptionDislikes": "\u4e0d\u559c\u6b61",
"OptionActors": "\u6f14\u54e1",
"OptionGuestStars": "\u7279\u9080\u660e\u661f",
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 1b5bd8440..51dccddff 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -305,20 +305,6 @@ namespace MediaBrowser.ServerApplication
{
var saveConfig = false;
- if (ServerConfigurationManager.Configuration.DlnaOptions != null)
- {
- ServerConfigurationManager.SaveConfiguration("dlna", ServerConfigurationManager.Configuration.DlnaOptions);
- ServerConfigurationManager.Configuration.DlnaOptions = null;
- saveConfig = true;
- }
-
- if (ServerConfigurationManager.Configuration.LiveTvOptions != null)
- {
- ServerConfigurationManager.SaveConfiguration("livetv", ServerConfigurationManager.Configuration.LiveTvOptions);
- ServerConfigurationManager.Configuration.LiveTvOptions = null;
- saveConfig = true;
- }
-
if (ServerConfigurationManager.Configuration.TvFileOrganizationOptions != null)
{
ServerConfigurationManager.SaveConfiguration("autoorganize", new AutoOrganizeOptions { TvOptions = ServerConfigurationManager.Configuration.TvFileOrganizationOptions });
diff --git a/MediaBrowser.Tests/MediaBrowser.Tests.csproj b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
index dc7393b01..315ec583e 100644
--- a/MediaBrowser.Tests/MediaBrowser.Tests.csproj
+++ b/MediaBrowser.Tests/MediaBrowser.Tests.csproj
@@ -50,7 +50,7 @@
</Otherwise>
</Choose>
<ItemGroup>
- <Compile Include="MediaEncoding\Subtitles\SsaParserTests.cs" />
+ <Compile Include="MediaEncoding\Subtitles\AssParserTests.cs" />
<Compile Include="MediaEncoding\Subtitles\SrtParserTests.cs" />
<Compile Include="MediaEncoding\Subtitles\VttWriterTest.cs" />
<Compile Include="Providers\MovieDbProviderTests.cs" />
@@ -93,7 +93,7 @@
<None Include="MediaEncoding\Subtitles\TestSubtitles\expected.vtt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
- <None Include="MediaEncoding\Subtitles\TestSubtitles\data.ssa">
+ <None Include="MediaEncoding\Subtitles\TestSubtitles\data.ass">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="MediaEncoding\Subtitles\TestSubtitles\unit.srt">
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs
index d869146fd..17687bc3a 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/SsaParserTests.cs
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/AssParserTests.cs
@@ -1,14 +1,13 @@
-using System;
+using MediaBrowser.MediaEncoding.Subtitles;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.IO;
using System.Threading;
-using MediaBrowser.MediaEncoding.Subtitles;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
[TestClass]
- public class SsaParserTests {
+ public class AssParserTests {
[TestMethod]
public void TestParse() {
@@ -21,7 +20,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
StartPositionTicks = 24000000,
EndPositionTicks = 72000000,
Text =
- "Senator, we're <br />making our final <br />approach into Coruscant."
+ "Senator, we're "+ParserValues.NewLine+"making our final "+ParserValues.NewLine+"approach into Coruscant."
},
new SubtitleTrackEvent {
Id = "2",
@@ -34,14 +33,14 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
Id = "3",
StartPositionTicks = 150400000,
EndPositionTicks = 180400000,
- Text = "It's <br />a <br />trap!"
+ Text = "It's "+ParserValues.NewLine+"a "+ParserValues.NewLine+"trap!"
}
}
};
var sut = new AssParser();
- var stream = File.OpenRead(@"MediaEncoding\Subtitles\TestSubtitles\data.ssa");
+ var stream = File.OpenRead(@"MediaEncoding\Subtitles\TestSubtitles\data.ass");
var result = sut.Parse(stream, CancellationToken.None);
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs b/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs
index 2c2c944b1..6724ca597 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/SrtParserTests.cs
@@ -5,17 +5,21 @@ using System.Threading;
using MediaBrowser.MediaEncoding.Subtitles;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
+namespace MediaBrowser.Tests.MediaEncoding.Subtitles
+{
[TestClass]
- public class SrtParserTests {
+ public class SrtParserTests
+ {
[TestMethod]
- public void TestParse() {
+ public void TestParse()
+ {
var expectedSubs =
- new SubtitleTrackInfo {
- TrackEvents = new List<SubtitleTrackEvent> {
+ new SubtitleTrackInfo
+ {
+ TrackEvents = new List<SubtitleTrackEvent> {
new SubtitleTrackEvent {
Id = "1",
StartPositionTicks = 24000000,
@@ -28,7 +32,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
StartPositionTicks = 157120000,
EndPositionTicks = 173990000,
Text =
- "Oh my god, Watch out!<br />It's coming!!"
+ "Oh my god, Watch out!"+ParserValues.NewLine+"It's coming!!"
},
new SubtitleTrackEvent {
Id = "3",
@@ -48,7 +52,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
StartPositionTicks = 320000000,
EndPositionTicks = 329990000,
Text =
- "This is a<br />new line, as is<br />this"
+ "This is a"+ParserValues.NewLine+"new line, as is"+ParserValues.NewLine+"this"
},
new SubtitleTrackEvent {
Id = "6",
@@ -86,7 +90,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
"Greater than (&lt;) and less than (&gt;) are shown"
}
}
- };
+ };
var sut = new SrtParser();
@@ -95,7 +99,7 @@ namespace MediaBrowser.Tests.MediaEncoding.Subtitles {
var result = sut.Parse(stream, CancellationToken.None);
Assert.IsNotNull(result);
- Assert.AreEqual(expectedSubs.TrackEvents.Count,result.TrackEvents.Count);
+ Assert.AreEqual(expectedSubs.TrackEvents.Count, result.TrackEvents.Count);
for (int i = 0; i < expectedSubs.TrackEvents.Count; i++)
{
Assert.AreEqual(expectedSubs.TrackEvents[i].Id, result.TrackEvents[i].Id);
diff --git a/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ssa b/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ass
index 3114a844a..3114a844a 100644
--- a/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ssa
+++ b/MediaBrowser.Tests/MediaEncoding/Subtitles/TestSubtitles/data.ass