浏览代码

Merge pull request #925 from Bond-009/newmaser

Merge 10.2.0 release branch back into master
Joshua M. Boniface 6 年之前
父节点
当前提交
9a38e4dc8a
共有 35 个文件被更改,包括 586 次插入419 次删除
  1. 1 0
      CONTRIBUTORS.md
  2. 7 6
      Dockerfile
  3. 22 10
      Dockerfile.arm
  4. 18 14
      Dockerfile.arm64
  5. 5 5
      Emby.Dlna/PlayTo/PlayToManager.cs
  6. 1 1
      Emby.Server.Implementations/ApplicationHost.cs
  7. 9 29
      Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
  8. 23 77
      Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
  9. 25 25
      Emby.Server.Implementations/Localization/Core/da.json
  10. 27 27
      Emby.Server.Implementations/Localization/Core/de.json
  11. 1 1
      Emby.Server.Implementations/Localization/Core/en-GB.json
  12. 1 1
      Emby.Server.Implementations/Localization/Core/en-US.json
  13. 23 23
      Emby.Server.Implementations/Localization/Core/es.json
  14. 1 1
      Emby.Server.Implementations/Localization/Core/fr.json
  15. 35 35
      Emby.Server.Implementations/Localization/Core/hu.json
  16. 4 4
      Emby.Server.Implementations/Localization/Core/it.json
  17. 94 94
      Emby.Server.Implementations/Localization/Core/kk.json
  18. 3 3
      Emby.Server.Implementations/Localization/Core/ms.json
  19. 18 18
      Emby.Server.Implementations/Localization/Core/nl.json
  20. 5 5
      Emby.Server.Implementations/Localization/Core/ru.json
  21. 15 25
      Emby.Server.Implementations/Updates/InstallationManager.cs
  22. 0 2
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  23. 4 1
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  24. 3 0
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  25. 4 1
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  26. 5 1
      MediaBrowser.Api/Playback/UniversalAudioService.cs
  27. 0 2
      MediaBrowser.Controller/Net/StaticResultOptions.cs
  28. 1 1
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  29. 1 1
      MediaBrowser.WebDashboard/jellyfin-web
  30. 2 2
      SharedVersion.cs
  31. 108 0
      deployment/debian-package-x64/pkg-src/changelog
  32. 6 1
      deployment/debian-package-x64/pkg-src/control
  33. 106 2
      deployment/fedora-package-x64/pkg-src/jellyfin.spec
  34. 2 1
      deployment/win-x64/package.sh
  35. 6 0
      hooks/pre_build

+ 1 - 0
CONTRIBUTORS.md

@@ -18,6 +18,7 @@
  - [dkanada](https://github.com/dkanada)
  - [dkanada](https://github.com/dkanada)
  - [LogicalPhallacy](https://github.com/LogicalPhallacy/)
  - [LogicalPhallacy](https://github.com/LogicalPhallacy/)
  - [RazeLighter777](https://github.com/RazeLighter777)
  - [RazeLighter777](https://github.com/RazeLighter777)
+ - [WillWill56](https://github.com/WillWill56)
 
 
 # Emby Contributors
 # Emby Contributors
 
 

+ 7 - 6
Dockerfile

@@ -3,9 +3,8 @@ ARG DOTNET_VERSION=2
 FROM microsoft/dotnet:${DOTNET_VERSION}-sdk as builder
 FROM microsoft/dotnet:${DOTNET_VERSION}-sdk as builder
 WORKDIR /repo
 WORKDIR /repo
 COPY . .
 COPY . .
-RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
- && dotnet clean \
- && dotnet publish \
+ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
+RUN dotnet publish \
     --configuration release \
     --configuration release \
     --output /jellyfin \
     --output /jellyfin \
     Jellyfin.Server
     Jellyfin.Server
@@ -18,9 +17,11 @@ RUN apt-get update \
    libfontconfig1 \
    libfontconfig1 \
  && apt-get clean autoclean \
  && apt-get clean autoclean \
  && apt-get autoremove \
  && apt-get autoremove \
- && rm -rf /var/lib/{apt,dpkg,cache,log}
+ && rm -rf /var/lib/{apt,dpkg,cache,log} \
+ && mkdir -p /cache /config /media \
+ && chmod 777 /cache /config /media
 COPY --from=ffmpeg / /
 COPY --from=ffmpeg / /
 COPY --from=builder /jellyfin /jellyfin
 COPY --from=builder /jellyfin /jellyfin
 EXPOSE 8096
 EXPOSE 8096
-VOLUME /config /media
-ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config
+VOLUME /cache /config /media
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config --cachedir /cache

+ 22 - 10
Dockerfile.arm

@@ -1,24 +1,36 @@
+# Requires binfm_misc registration
+# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
 ARG DOTNET_VERSION=3.0
 ARG DOTNET_VERSION=3.0
 
 
 
 
-FROM microsoft/dotnet:${DOTNET_VERSION}-sdk-stretch-arm32v7 as builder
+FROM multiarch/qemu-user-static:x86_64-arm as qemu
+FROM alpine as qemu_extract
+COPY --from=qemu /usr/bin qemu-arm-static.tar.gz
+RUN tar -xzvf qemu-arm-static.tar.gz
+
+FROM microsoft/dotnet:${DOTNET_VERSION}-sdk-stretch as builder
 WORKDIR /repo
 WORKDIR /repo
 COPY . .
 COPY . .
-#TODO Remove or update the sed line when we update dotnet version.
-RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
- && find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \; \
- && dotnet clean -maxcpucount:1 \
- && dotnet publish \
-    -maxcpucount:1 \
+ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
+# TODO Remove or update the sed line when we update dotnet version.
+RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
+# Discard objs - may cause failures if exists
+RUN find . -type d -name obj | xargs -r rm -r
+# Build
+RUN dotnet publish \
+    -r linux-arm \
     --configuration release \
     --configuration release \
     --output /jellyfin \
     --output /jellyfin \
     Jellyfin.Server
     Jellyfin.Server
 
 
 
 
 FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm32v7
 FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm32v7
+COPY --from=qemu_extract qemu-arm-static /usr/bin
 RUN apt-get update \
 RUN apt-get update \
- && apt-get install -y ffmpeg
+ && apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
+ && mkdir -p /cache /config /media \
+ && chmod 777 /cache /config /media
 COPY --from=builder /jellyfin /jellyfin
 COPY --from=builder /jellyfin /jellyfin
 EXPOSE 8096
 EXPOSE 8096
-VOLUME /config /media
-ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config
+VOLUME /cache /config /media
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config --cachedir /cache

+ 18 - 14
Dockerfile.arm64

@@ -1,33 +1,37 @@
-# Requires binfm_misc registration for aarch64
+# Requires binfm_misc registration
 # https://github.com/multiarch/qemu-user-static#binfmt_misc-register
 # https://github.com/multiarch/qemu-user-static#binfmt_misc-register
 ARG DOTNET_VERSION=3.0
 ARG DOTNET_VERSION=3.0
 
 
 
 
 FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
 FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
 FROM alpine as qemu_extract
 FROM alpine as qemu_extract
-COPY --from=qemu /usr/bin qemu_user_static.tgz
-RUN tar -xzvf qemu_user_static.tgz
+COPY --from=qemu /usr/bin qemu-aarch64-static.tar.gz
+RUN tar -xzvf qemu-aarch64-static.tar.gz
 
 
 
 
-FROM microsoft/dotnet:${DOTNET_VERSION}-sdk-stretch-arm64v8 as builder
-COPY --from=qemu_extract qemu-* /usr/bin
+FROM microsoft/dotnet:${DOTNET_VERSION}-sdk-stretch as builder
 WORKDIR /repo
 WORKDIR /repo
 COPY . .
 COPY . .
-#TODO Remove or update the sed line when we update dotnet version.
-RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \
- && find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \; \
- && dotnet clean \
- && dotnet publish \
+ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
+# TODO Remove or update the sed line when we update dotnet version.
+RUN find . -type f -exec sed -i 's/netcoreapp2.1/netcoreapp3.0/g' {} \;
+# Discard objs - may cause failures if exists
+RUN find . -type d -name obj | xargs -r rm -r
+# Build
+RUN dotnet publish \
+    -r linux-arm64 \
     --configuration release \
     --configuration release \
     --output /jellyfin \
     --output /jellyfin \
     Jellyfin.Server
     Jellyfin.Server
 
 
 
 
 FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm64v8
 FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm64v8
+COPY --from=qemu_extract qemu-aarch64-static /usr/bin
 RUN apt-get update \
 RUN apt-get update \
- && apt-get install -y ffmpeg
-COPY --from=qemu_extract qemu-* /usr/bin
+ && apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
+ && mkdir -p /cache /config /media \
+ && chmod 777 /cache /config /media
 COPY --from=builder /jellyfin /jellyfin
 COPY --from=builder /jellyfin /jellyfin
 EXPOSE 8096
 EXPOSE 8096
-VOLUME /config /media
-ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config
+VOLUME /cache /config /media
+ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config --cachedir /cache

+ 5 - 5
Emby.Dlna/PlayTo/PlayToManager.cs

@@ -89,11 +89,6 @@ namespace Emby.Dlna.PlayTo
                 return;
                 return;
             }
             }
 
 
-            if (_sessionManager.Sessions.Any(i => usn.IndexOf(i.DeviceId, StringComparison.OrdinalIgnoreCase) != -1))
-            {
-                return;
-            }
-
             var cancellationToken = _disposeCancellationTokenSource.Token;
             var cancellationToken = _disposeCancellationTokenSource.Token;
 
 
             await _sessionLock.WaitAsync(cancellationToken).ConfigureAwait(false);
             await _sessionLock.WaitAsync(cancellationToken).ConfigureAwait(false);
@@ -105,6 +100,11 @@ namespace Emby.Dlna.PlayTo
                     return;
                     return;
                 }
                 }
 
 
+                if (_sessionManager.Sessions.Any(i => usn.IndexOf(i.DeviceId, StringComparison.OrdinalIgnoreCase) != -1))
+                {
+                    return;
+                }
+
                 await AddDevice(info, location, cancellationToken).ConfigureAwait(false);
                 await AddDevice(info, location, cancellationToken).ConfigureAwait(false);
             }
             }
             catch (OperationCanceledException)
             catch (OperationCanceledException)

+ 1 - 1
Emby.Server.Implementations/ApplicationHost.cs

@@ -665,7 +665,7 @@ namespace Emby.Server.Implementations
             SocketFactory = new SocketFactory();
             SocketFactory = new SocketFactory();
             serviceCollection.AddSingleton(SocketFactory);
             serviceCollection.AddSingleton(SocketFactory);
 
 
-            InstallationManager = new InstallationManager(LoggerFactory, this, ApplicationPaths, HttpClient, JsonSerializer, ServerConfigurationManager, FileSystemManager, CryptographyProvider, PackageRuntime);
+            InstallationManager = new InstallationManager(LoggerFactory, this, ApplicationPaths, HttpClient, JsonSerializer, ServerConfigurationManager, FileSystemManager, CryptographyProvider, ZipClient, PackageRuntime);
             serviceCollection.AddSingleton(InstallationManager);
             serviceCollection.AddSingleton(InstallationManager);
 
 
             ZipClient = new ZipClient(FileSystemManager);
             ZipClient = new ZipClient(FileSystemManager);

+ 9 - 29
Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs

@@ -66,11 +66,6 @@ namespace Emby.Server.Implementations.HttpClientManager
 
 
             // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
             // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
             ServicePointManager.Expect100Continue = false;
             ServicePointManager.Expect100Continue = false;
-
-#if NET46
-// Trakt requests sometimes fail without this
-            ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
-#endif
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -106,23 +101,6 @@ namespace Emby.Server.Implementations.HttpClientManager
             return client;
             return client;
         }
         }
 
 
-        private static WebRequest CreateWebRequest(string url)
-        {
-            try
-            {
-                return WebRequest.Create(url);
-            }
-            catch (NotSupportedException)
-            {
-                //Webrequest creation does fail on MONO randomly when using WebRequest.Create
-                //the issue occurs in the GetCreator method here: http://www.oschina.net/code/explore/mono-2.8.1/mcs/class/System/System.Net/WebRequest.cs
-
-                var type = Type.GetType("System.Net.HttpRequestCreator, System, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089");
-                var creator = Activator.CreateInstance(type, nonPublic: true) as IWebRequestCreate;
-                return creator.Create(new Uri(url)) as HttpWebRequest;
-            }
-        }
-
         private WebRequest GetRequest(HttpRequestOptions options, string method)
         private WebRequest GetRequest(HttpRequestOptions options, string method)
         {
         {
             string url = options.Url;
             string url = options.Url;
@@ -135,7 +113,7 @@ namespace Emby.Server.Implementations.HttpClientManager
                 url = url.Replace(userInfo + "@", string.Empty);
                 url = url.Replace(userInfo + "@", string.Empty);
             }
             }
 
 
-            var request = CreateWebRequest(url);
+            var request = WebRequest.Create(url);
 
 
             if (request is HttpWebRequest httpWebRequest)
             if (request is HttpWebRequest httpWebRequest)
             {
             {
@@ -627,14 +605,16 @@ namespace Emby.Server.Implementations.HttpClientManager
 
 
                 var exception = new HttpException(webException.Message, webException);
                 var exception = new HttpException(webException.Message, webException);
 
 
-                var response = webException.Response as HttpWebResponse;
-                if (response != null)
+                using (var response = webException.Response as HttpWebResponse)
                 {
                 {
-                    exception.StatusCode = response.StatusCode;
-
-                    if ((int)response.StatusCode == 429)
+                    if (response != null)
                     {
                     {
-                        client.LastTimeout = DateTime.UtcNow;
+                        exception.StatusCode = response.StatusCode;
+
+                        if ((int)response.StatusCode == 429)
+                        {
+                            client.LastTimeout = DateTime.UtcNow;
+                        }
                     }
                     }
                 }
                 }
 
 

+ 23 - 77
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -422,18 +422,20 @@ namespace Emby.Server.Implementations.HttpServer
         /// <summary>
         /// <summary>
         /// Pres the process optimized result.
         /// Pres the process optimized result.
         /// </summary>
         /// </summary>
-        private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType)
+        private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options)
         {
         {
             bool noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
             bool noCache = (requestContext.Headers.Get("Cache-Control") ?? string.Empty).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
+            AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified);
 
 
             if (!noCache)
             if (!noCache)
             {
             {
-                if (IsNotModified(requestContext, cacheKey))
+                DateTime.TryParse(requestContext.Headers.Get("If-Modified-Since"), out var ifModifiedSinceHeader);
+
+                if (IsNotModified(ifModifiedSinceHeader, options.CacheDuration, options.DateLastModified))
                 {
                 {
-                    AddAgeHeader(responseHeaders, lastDateModified);
-                    AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration);
+                    AddAgeHeader(responseHeaders, options.DateLastModified);
 
 
-                    var result = new HttpResult(Array.Empty<byte>(), contentType ?? "text/html", HttpStatusCode.NotModified);
+                    var result = new HttpResult(Array.Empty<byte>(), options.ContentType ?? "text/html", HttpStatusCode.NotModified);
 
 
                     AddResponseHeaders(result, responseHeaders);
                     AddResponseHeaders(result, responseHeaders);
 
 
@@ -441,8 +443,6 @@ namespace Emby.Server.Implementations.HttpServer
                 }
                 }
             }
             }
 
 
-            AddCachingHeaders(responseHeaders, cacheKeyString, cacheDuration);
-
             return null;
             return null;
         }
         }
 
 
@@ -487,9 +487,6 @@ namespace Emby.Server.Implementations.HttpServer
                 options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
                 options.DateLastModified = _fileSystem.GetLastWriteTimeUtc(path);
             }
             }
 
 
-            var cacheKey = path + options.DateLastModified.Value.Ticks;
-
-            options.CacheKey = cacheKey.GetMD5();
             options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));
             options.ContentFactory = () => Task.FromResult(GetFileStream(path, fileShare));
 
 
             options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@@ -520,7 +517,6 @@ namespace Emby.Server.Implementations.HttpServer
             return GetStaticResult(requestContext, new StaticResultOptions
             return GetStaticResult(requestContext, new StaticResultOptions
             {
             {
                 CacheDuration = cacheDuration,
                 CacheDuration = cacheDuration,
-                CacheKey = cacheKey,
                 ContentFactory = factoryFn,
                 ContentFactory = factoryFn,
                 ContentType = contentType,
                 ContentType = contentType,
                 DateLastModified = lastDateModified,
                 DateLastModified = lastDateModified,
@@ -534,14 +530,10 @@ namespace Emby.Server.Implementations.HttpServer
             options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             options.ResponseHeaders = options.ResponseHeaders ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
 
             var contentType = options.ContentType;
             var contentType = options.ContentType;
-            var etag = requestContext.Headers.Get("If-None-Match");
-            var cacheKey = etag != null ? new Guid(etag.Trim('\"')) : Guid.Empty;
-            if (!cacheKey.Equals(Guid.Empty))
+            if (!string.IsNullOrEmpty(requestContext.Headers.Get("If-Modified-Since")))
             {
             {
-                var key = cacheKey.ToString("N");
-
                 // See if the result is already cached in the browser
                 // See if the result is already cached in the browser
-                var result = GetCachedResult(requestContext, options.ResponseHeaders, cacheKey, key, options.DateLastModified, options.CacheDuration, contentType);
+                var result = GetCachedResult(requestContext, options.ResponseHeaders, options);
 
 
                 if (result != null)
                 if (result != null)
                 {
                 {
@@ -553,6 +545,8 @@ namespace Emby.Server.Implementations.HttpServer
             var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase);
             var isHeadRequest = options.IsHeadRequest || string.Equals(requestContext.Verb, "HEAD", StringComparison.OrdinalIgnoreCase);
             var factoryFn = options.ContentFactory;
             var factoryFn = options.ContentFactory;
             var responseHeaders = options.ResponseHeaders;
             var responseHeaders = options.ResponseHeaders;
+            AddCachingHeaders(responseHeaders, options.CacheDuration, false, options.DateLastModified);
+            AddAgeHeader(responseHeaders, options.DateLastModified);
 
 
             var rangeHeader = requestContext.Headers.Get("Range");
             var rangeHeader = requestContext.Headers.Get("Range");
 
 
@@ -566,21 +560,10 @@ namespace Emby.Server.Implementations.HttpServer
                 };
                 };
 
 
                 AddResponseHeaders(hasHeaders, options.ResponseHeaders);
                 AddResponseHeaders(hasHeaders, options.ResponseHeaders);
-                // Generate an ETag based on identifying information - TODO read contents from filesystem instead?
-                var responseId = $"{hasHeaders.ContentType}{options.Path}{hasHeaders.TotalContentLength}";
-                var hashedId = MD5.Create().ComputeHash(Encoding.Default.GetBytes(responseId));
-                hasHeaders.Headers["ETag"] = new Guid(hashedId).ToString("N");
-
                 return hasHeaders;
                 return hasHeaders;
             }
             }
 
 
             var stream = await factoryFn().ConfigureAwait(false);
             var stream = await factoryFn().ConfigureAwait(false);
-            // Generate an etag based on stream content
-            var streamHash = MD5.Create().ComputeHash(stream);
-            var newEtag = new Guid(streamHash).ToString("N");
-
-            // reset position so the response can re-use it -- TODO is this ok?
-            stream.Position = 0;
 
 
             var totalContentLength = options.ContentLength;
             var totalContentLength = options.ContentLength;
             if (!totalContentLength.HasValue)
             if (!totalContentLength.HasValue)
@@ -603,7 +586,6 @@ namespace Emby.Server.Implementations.HttpServer
                 };
                 };
 
 
                 AddResponseHeaders(hasHeaders, options.ResponseHeaders);
                 AddResponseHeaders(hasHeaders, options.ResponseHeaders);
-                hasHeaders.Headers["ETag"] = newEtag;
                 return hasHeaders;
                 return hasHeaders;
             }
             }
             else
             else
@@ -628,7 +610,6 @@ namespace Emby.Server.Implementations.HttpServer
                 };
                 };
 
 
                 AddResponseHeaders(hasHeaders, options.ResponseHeaders);
                 AddResponseHeaders(hasHeaders, options.ResponseHeaders);
-                hasHeaders.Headers["ETag"] = newEtag;
                 return hasHeaders;
                 return hasHeaders;
             }
             }
         }
         }
@@ -641,37 +622,28 @@ namespace Emby.Server.Implementations.HttpServer
         /// <summary>
         /// <summary>
         /// Adds the caching responseHeaders.
         /// Adds the caching responseHeaders.
         /// </summary>
         /// </summary>
-        private void AddCachingHeaders(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration)
+        private void AddCachingHeaders(IDictionary<string, string> responseHeaders, TimeSpan? cacheDuration,
+            bool noCache, DateTime? lastModifiedDate)
         {
         {
-            if (cacheDuration.HasValue)
-            {
-                responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds);
-            }
-            else if (!string.IsNullOrEmpty(cacheKey))
-            {
-                responseHeaders["Cache-Control"] = "public";
-            }
-            else
+            if (noCache)
             {
             {
                 responseHeaders["Cache-Control"] = "no-cache, no-store, must-revalidate";
                 responseHeaders["Cache-Control"] = "no-cache, no-store, must-revalidate";
                 responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
                 responseHeaders["pragma"] = "no-cache, no-store, must-revalidate";
+                return;
             }
             }
 
 
-            AddExpiresHeader(responseHeaders, cacheKey, cacheDuration);
-        }
-
-        /// <summary>
-        /// Adds the expires header.
-        /// </summary>
-        private static void AddExpiresHeader(IDictionary<string, string> responseHeaders, string cacheKey, TimeSpan? cacheDuration)
-        {
             if (cacheDuration.HasValue)
             if (cacheDuration.HasValue)
             {
             {
-                responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r");
+                responseHeaders["Cache-Control"] = "public, max-age=" + cacheDuration.Value.TotalSeconds;
             }
             }
-            else if (string.IsNullOrEmpty(cacheKey))
+            else
             {
             {
-                responseHeaders["Expires"] = "-1";
+                responseHeaders["Cache-Control"] = "public";
+            }
+
+            if (lastModifiedDate.HasValue)
+            {
+                responseHeaders["Last-Modified"] = lastModifiedDate.ToString();
             }
             }
         }
         }
 
 
@@ -687,32 +659,6 @@ namespace Emby.Server.Implementations.HttpServer
                 responseHeaders["Age"] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture);
                 responseHeaders["Age"] = Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture);
             }
             }
         }
         }
-        /// <summary>
-        /// Determines whether [is not modified] [the specified cache key].
-        /// </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>
-        /// <returns><c>true</c> if [is not modified] [the specified cache key]; otherwise, <c>false</c>.</returns>
-        private bool IsNotModified(IRequest requestContext, Guid cacheKey)
-        {
-            var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match");
-
-            bool hasCacheKey = !cacheKey.Equals(Guid.Empty);
-
-            // Validate If-None-Match
-            if (hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader))
-            {
-                if (Guid.TryParse(ifNoneMatchHeader, out var ifNoneMatch)
-                    && cacheKey.Equals(ifNoneMatch))
-                {
-                    return true;
-                }
-            }
-
-            return false;
-        }
 
 
         /// <summary>
         /// <summary>
         /// Determines whether [is not modified] [the specified if modified since].
         /// Determines whether [is not modified] [the specified if modified since].

+ 25 - 25
Emby.Server.Implementations/Localization/Core/da.json

@@ -2,10 +2,10 @@
     "Albums": "Album",
     "Albums": "Album",
     "AppDeviceValues": "App: {0}, Enhed: {1}",
     "AppDeviceValues": "App: {0}, Enhed: {1}",
     "Application": "Applikation",
     "Application": "Applikation",
-    "Artists": "Kunstner",
+    "Artists": "Kunstnere",
     "AuthenticationSucceededWithUserName": "{0} bekræftet med succes",
     "AuthenticationSucceededWithUserName": "{0} bekræftet med succes",
     "Books": "Bøger",
     "Books": "Bøger",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "Et nyt kamerabillede er blevet uploadet fra {0}",
     "Channels": "Kanaler",
     "Channels": "Kanaler",
     "ChapterNameValue": "Kapitel {0}",
     "ChapterNameValue": "Kapitel {0}",
     "Collections": "Samlinger",
     "Collections": "Samlinger",
@@ -14,41 +14,41 @@
     "FailedLoginAttemptWithUserName": "Fejlet loginforsøg fra {0}",
     "FailedLoginAttemptWithUserName": "Fejlet loginforsøg fra {0}",
     "Favorites": "Favoritter",
     "Favorites": "Favoritter",
     "Folders": "Mapper",
     "Folders": "Mapper",
-    "Genres": "Genre",
+    "Genres": "Genrer",
     "HeaderAlbumArtists": "Albumkunstnere",
     "HeaderAlbumArtists": "Albumkunstnere",
-    "HeaderCameraUploads": "Camera Uploads",
+    "HeaderCameraUploads": "Kamera Uploads",
     "HeaderContinueWatching": "Fortsæt Afspilning",
     "HeaderContinueWatching": "Fortsæt Afspilning",
     "HeaderFavoriteAlbums": "Favoritalbum",
     "HeaderFavoriteAlbums": "Favoritalbum",
     "HeaderFavoriteArtists": "Favoritkunstnere",
     "HeaderFavoriteArtists": "Favoritkunstnere",
-    "HeaderFavoriteEpisodes": "Favoritepisoder",
-    "HeaderFavoriteShows": "Favorit serier",
-    "HeaderFavoriteSongs": "Favoritsange",
+    "HeaderFavoriteEpisodes": "Favorit-afsnit",
+    "HeaderFavoriteShows": "Favorit-serier",
+    "HeaderFavoriteSongs": "Favorit-sange",
     "HeaderLiveTV": "Live TV",
     "HeaderLiveTV": "Live TV",
     "HeaderNextUp": "Næste",
     "HeaderNextUp": "Næste",
-    "HeaderRecordingGroups": "Optagegrupper",
+    "HeaderRecordingGroups": "Optagelsesgrupper",
     "HomeVideos": "Hjemmevideoer",
     "HomeVideos": "Hjemmevideoer",
-    "Inherit": "Arv",
+    "Inherit": "Nedarv",
     "ItemAddedWithName": "{0} blev tilføjet til biblioteket",
     "ItemAddedWithName": "{0} blev tilføjet til biblioteket",
     "ItemRemovedWithName": "{0} blev fjernet fra biblioteket",
     "ItemRemovedWithName": "{0} blev fjernet fra biblioteket",
     "LabelIpAddressValue": "IP-adresse: {0}",
     "LabelIpAddressValue": "IP-adresse: {0}",
     "LabelRunningTimeValue": "Spilletid: {0}",
     "LabelRunningTimeValue": "Spilletid: {0}",
     "Latest": "Seneste",
     "Latest": "Seneste",
     "MessageApplicationUpdated": "Jellyfin Server er blevet opdateret",
     "MessageApplicationUpdated": "Jellyfin Server er blevet opdateret",
-    "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
-    "MessageNamedServerConfigurationUpdatedWithValue": "Server konfigurationssektion {0} er blevet opdateret",
-    "MessageServerConfigurationUpdated": "Serverkonfiguration er blevet opdateret",
+    "MessageApplicationUpdatedTo": "Jellyfin Server er blevet opdateret til {0}",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Serverkonfigurationsafsnit {0} er blevet opdateret",
+    "MessageServerConfigurationUpdated": "Serverkonfigurationen er blevet opdateret",
     "MixedContent": "Blandet indhold",
     "MixedContent": "Blandet indhold",
     "Movies": "Film",
     "Movies": "Film",
     "Music": "Musik",
     "Music": "Musik",
     "MusicVideos": "Musikvideoer",
     "MusicVideos": "Musikvideoer",
-    "NameInstallFailed": "{0} installation failed",
+    "NameInstallFailed": "{0} installationen mislykkedes",
     "NameSeasonNumber": "Sæson {0}",
     "NameSeasonNumber": "Sæson {0}",
-    "NameSeasonUnknown": "Season Unknown",
-    "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
+    "NameSeasonUnknown": "Ukendt Sæson",
+    "NewVersionIsAvailable": "En ny version af Jellyfin Server er tilgængelig til download.",
     "NotificationOptionApplicationUpdateAvailable": "Opdatering til applikation tilgængelig",
     "NotificationOptionApplicationUpdateAvailable": "Opdatering til applikation tilgængelig",
     "NotificationOptionApplicationUpdateInstalled": "Opdatering til applikation installeret",
     "NotificationOptionApplicationUpdateInstalled": "Opdatering til applikation installeret",
-    "NotificationOptionAudioPlayback": "Audioafspilning påbegyndt",
-    "NotificationOptionAudioPlaybackStopped": "Audioafspilning stoppet",
+    "NotificationOptionAudioPlayback": "Lydafspilning påbegyndt",
+    "NotificationOptionAudioPlaybackStopped": "Lydafspilning stoppet",
     "NotificationOptionCameraImageUploaded": "Kamerabillede uploadet",
     "NotificationOptionCameraImageUploaded": "Kamerabillede uploadet",
     "NotificationOptionInstallationFailed": "Installationsfejl",
     "NotificationOptionInstallationFailed": "Installationsfejl",
     "NotificationOptionNewLibraryContent": "Nyt indhold tilføjet",
     "NotificationOptionNewLibraryContent": "Nyt indhold tilføjet",
@@ -70,16 +70,16 @@
     "ProviderValue": "Udbyder: {0}",
     "ProviderValue": "Udbyder: {0}",
     "ScheduledTaskFailedWithName": "{0} fejlet",
     "ScheduledTaskFailedWithName": "{0} fejlet",
     "ScheduledTaskStartedWithName": "{0} påbegyndt",
     "ScheduledTaskStartedWithName": "{0} påbegyndt",
-    "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
-    "Shows": "Shows",
+    "ServerNameNeedsToBeRestarted": "{0} skal genstartes",
+    "Shows": "Serier",
     "Songs": "Sange",
     "Songs": "Sange",
-    "StartupEmbyServerIsLoading": "Jellyfin Server indlæser. Prøv venligst igen om kort tid.",
+    "StartupEmbyServerIsLoading": "Jellyfin Server er i gang med at starte op. Prøv venligst igen om lidt.",
     "SubtitleDownloadFailureForItem": "Fejlet i download af undertekster for {0}",
     "SubtitleDownloadFailureForItem": "Fejlet i download af undertekster for {0}",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Undertekster kunne ikke downloades fra {0} til {1}",
     "SubtitlesDownloadedForItem": "Undertekster downloadet for {0}",
     "SubtitlesDownloadedForItem": "Undertekster downloadet for {0}",
     "Sync": "Synk",
     "Sync": "Synk",
     "System": "System",
     "System": "System",
-    "TvShows": "TV Shows",
+    "TvShows": "TV serier",
     "User": "Bruger",
     "User": "Bruger",
     "UserCreatedWithName": "Bruger {0} er blevet oprettet",
     "UserCreatedWithName": "Bruger {0} er blevet oprettet",
     "UserDeletedWithName": "Brugeren {0} er blevet slettet",
     "UserDeletedWithName": "Brugeren {0} er blevet slettet",
@@ -88,10 +88,10 @@
     "UserOfflineFromDevice": "{0} har afbrudt fra {1}",
     "UserOfflineFromDevice": "{0} har afbrudt fra {1}",
     "UserOnlineFromDevice": "{0} er online fra {1}",
     "UserOnlineFromDevice": "{0} er online fra {1}",
     "UserPasswordChangedWithName": "Adgangskode er ændret for bruger {0}",
     "UserPasswordChangedWithName": "Adgangskode er ændret for bruger {0}",
-    "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
+    "UserPolicyUpdatedWithName": "Brugerpolitik er blevet opdateret for {0}",
     "UserStartedPlayingItemWithValues": "{0} har påbegyndt afspilning af {1}",
     "UserStartedPlayingItemWithValues": "{0} har påbegyndt afspilning af {1}",
-    "UserStoppedPlayingItemWithValues": "{0} har afsluttet afspilning af {1}",
-    "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+    "UserStoppedPlayingItemWithValues": "{0} har afsluttet afspilning af {1} på {2}",
+    "ValueHasBeenAddedToLibrary": "{0} er blevet tilføjet til dit mediebibliotek",
     "ValueSpecialEpisodeName": "Special - {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "VersionNumber": "Version {0}"
     "VersionNumber": "Version {0}"
 }
 }

+ 27 - 27
Emby.Server.Implementations/Localization/Core/de.json

@@ -3,61 +3,61 @@
     "AppDeviceValues": "App: {0}, Gerät: {1}",
     "AppDeviceValues": "App: {0}, Gerät: {1}",
     "Application": "Anwendung",
     "Application": "Anwendung",
     "Artists": "Interpreten",
     "Artists": "Interpreten",
-    "AuthenticationSucceededWithUserName": "{0} erfolgreich authentifiziert",
+    "AuthenticationSucceededWithUserName": "{0} hat sich angemeldet",
     "Books": "Bücher",
     "Books": "Bücher",
-    "CameraImageUploadedFrom": "Ein neues Bild wurde hochgeladen von {0}",
+    "CameraImageUploadedFrom": "Ein neues Foto wurde hochgeladen von {0}",
     "Channels": "Kanäle",
     "Channels": "Kanäle",
     "ChapterNameValue": "Kapitel {0}",
     "ChapterNameValue": "Kapitel {0}",
     "Collections": "Sammlungen",
     "Collections": "Sammlungen",
     "DeviceOfflineWithName": "{0} wurde getrennt",
     "DeviceOfflineWithName": "{0} wurde getrennt",
-    "DeviceOnlineWithName": "{0} ist verbunden",
+    "DeviceOnlineWithName": "{0} hat sich verbunden",
     "FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
     "FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}",
     "Favorites": "Favoriten",
     "Favorites": "Favoriten",
     "Folders": "Verzeichnisse",
     "Folders": "Verzeichnisse",
     "Genres": "Genres",
     "Genres": "Genres",
-    "HeaderAlbumArtists": "Album-Künstler",
-    "HeaderCameraUploads": "Kamera Uploads",
+    "HeaderAlbumArtists": "Album-Interpreten",
+    "HeaderCameraUploads": "Kamera-Uploads",
     "HeaderContinueWatching": "Weiterschauen",
     "HeaderContinueWatching": "Weiterschauen",
     "HeaderFavoriteAlbums": "Lieblingsalben",
     "HeaderFavoriteAlbums": "Lieblingsalben",
-    "HeaderFavoriteArtists": "Interpreten Favoriten",
+    "HeaderFavoriteArtists": "Lieblings-Interpreten",
     "HeaderFavoriteEpisodes": "Lieblingsepisoden",
     "HeaderFavoriteEpisodes": "Lieblingsepisoden",
     "HeaderFavoriteShows": "Lieblingsserien",
     "HeaderFavoriteShows": "Lieblingsserien",
-    "HeaderFavoriteSongs": "Lieder Favoriten",
-    "HeaderLiveTV": "Live TV",
+    "HeaderFavoriteSongs": "Lieblingslieder",
+    "HeaderLiveTV": "Live-TV",
     "HeaderNextUp": "Als Nächstes",
     "HeaderNextUp": "Als Nächstes",
     "HeaderRecordingGroups": "Aufnahme-Gruppen",
     "HeaderRecordingGroups": "Aufnahme-Gruppen",
     "HomeVideos": "Heimvideos",
     "HomeVideos": "Heimvideos",
     "Inherit": "Übernehmen",
     "Inherit": "Übernehmen",
     "ItemAddedWithName": "{0} wurde der Bibliothek hinzugefügt",
     "ItemAddedWithName": "{0} wurde der Bibliothek hinzugefügt",
     "ItemRemovedWithName": "{0} wurde aus der Bibliothek entfernt",
     "ItemRemovedWithName": "{0} wurde aus der Bibliothek entfernt",
-    "LabelIpAddressValue": "IP Adresse: {0}",
+    "LabelIpAddressValue": "IP-Adresse: {0}",
     "LabelRunningTimeValue": "Laufzeit: {0}",
     "LabelRunningTimeValue": "Laufzeit: {0}",
     "Latest": "Neueste",
     "Latest": "Neueste",
-    "MessageApplicationUpdated": "Jellyfin Server wurde auf den neusten Stand gebracht.",
-    "MessageApplicationUpdatedTo": "Jellyfin Server wurde auf Version {0} aktualisiert",
+    "MessageApplicationUpdated": "Jellyfin-Server wurde aktualisiert",
+    "MessageApplicationUpdatedTo": "Jellyfin-Server wurde auf Version {0} aktualisiert",
     "MessageNamedServerConfigurationUpdatedWithValue": "Der Server Einstellungsbereich {0} wurde aktualisiert",
     "MessageNamedServerConfigurationUpdatedWithValue": "Der Server Einstellungsbereich {0} wurde aktualisiert",
-    "MessageServerConfigurationUpdated": "Server Einstellungen wurden aktualisiert",
+    "MessageServerConfigurationUpdated": "Servereinstellungen wurden aktualisiert",
     "MixedContent": "Gemischte Inhalte",
     "MixedContent": "Gemischte Inhalte",
     "Movies": "Filme",
     "Movies": "Filme",
     "Music": "Musik",
     "Music": "Musik",
     "MusicVideos": "Musikvideos",
     "MusicVideos": "Musikvideos",
-    "NameInstallFailed": "{0} Installation fehlgeschlagen",
+    "NameInstallFailed": "Installation von {0} fehlgeschlagen",
     "NameSeasonNumber": "Staffel {0}",
     "NameSeasonNumber": "Staffel {0}",
     "NameSeasonUnknown": "Staffel unbekannt",
     "NameSeasonUnknown": "Staffel unbekannt",
-    "NewVersionIsAvailable": "Eine neue Version von Jellyfin Server steht zum Download bereit.",
+    "NewVersionIsAvailable": "Eine neue Version von Jellyfin-Server steht zum Download bereit.",
     "NotificationOptionApplicationUpdateAvailable": "Anwendungsaktualisierung verfügbar",
     "NotificationOptionApplicationUpdateAvailable": "Anwendungsaktualisierung verfügbar",
     "NotificationOptionApplicationUpdateInstalled": "Anwendungsaktualisierung installiert",
     "NotificationOptionApplicationUpdateInstalled": "Anwendungsaktualisierung installiert",
     "NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
     "NotificationOptionAudioPlayback": "Audiowiedergabe gestartet",
     "NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
     "NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt",
-    "NotificationOptionCameraImageUploaded": "Kamera Bild hochgeladen",
+    "NotificationOptionCameraImageUploaded": "Foto hochgeladen",
     "NotificationOptionInstallationFailed": "Installationsfehler",
     "NotificationOptionInstallationFailed": "Installationsfehler",
     "NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt",
     "NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt",
-    "NotificationOptionPluginError": "Plugin Fehler",
+    "NotificationOptionPluginError": "Plugin-Fehler",
     "NotificationOptionPluginInstalled": "Plugin installiert",
     "NotificationOptionPluginInstalled": "Plugin installiert",
     "NotificationOptionPluginUninstalled": "Plugin deinstalliert",
     "NotificationOptionPluginUninstalled": "Plugin deinstalliert",
     "NotificationOptionPluginUpdateInstalled": "Pluginaktualisierung installiert",
     "NotificationOptionPluginUpdateInstalled": "Pluginaktualisierung installiert",
     "NotificationOptionServerRestartRequired": "Serverneustart notwendig",
     "NotificationOptionServerRestartRequired": "Serverneustart notwendig",
-    "NotificationOptionTaskFailed": "Geplante Aufgaben fehlgeschlagen",
+    "NotificationOptionTaskFailed": "Geplante Aufgabe fehlgeschlagen",
     "NotificationOptionUserLockedOut": "Benutzer ausgeschlossen",
     "NotificationOptionUserLockedOut": "Benutzer ausgeschlossen",
     "NotificationOptionVideoPlayback": "Videowiedergabe gestartet",
     "NotificationOptionVideoPlayback": "Videowiedergabe gestartet",
     "NotificationOptionVideoPlaybackStopped": "Videowiedergabe gestoppt",
     "NotificationOptionVideoPlaybackStopped": "Videowiedergabe gestoppt",
@@ -68,18 +68,18 @@
     "PluginUninstalledWithName": "{0} wurde deinstalliert",
     "PluginUninstalledWithName": "{0} wurde deinstalliert",
     "PluginUpdatedWithName": "{0} wurde aktualisiert",
     "PluginUpdatedWithName": "{0} wurde aktualisiert",
     "ProviderValue": "Anbieter: {0}",
     "ProviderValue": "Anbieter: {0}",
-    "ScheduledTaskFailedWithName": "{0} fehlgeschlagen",
-    "ScheduledTaskStartedWithName": "{0} gestartet",
+    "ScheduledTaskFailedWithName": "{0} ist fehlgeschlagen",
+    "ScheduledTaskStartedWithName": "{0} wurde gestartet",
     "ServerNameNeedsToBeRestarted": "{0} muss neu gestartet werden",
     "ServerNameNeedsToBeRestarted": "{0} muss neu gestartet werden",
     "Shows": "Serien",
     "Shows": "Serien",
     "Songs": "Songs",
     "Songs": "Songs",
-    "StartupEmbyServerIsLoading": "Jellyfin Server startet, bitte versuche es gleich noch einmal.",
+    "StartupEmbyServerIsLoading": "Jellyfin-Server startet, bitte versuche es gleich noch einmal.",
     "SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen für {0}",
     "SubtitleDownloadFailureForItem": "Download der Untertitel fehlgeschlagen für {0}",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Untertitel von {0} für {1} konnten nicht heruntergeladen werden",
     "SubtitlesDownloadedForItem": "Untertitel heruntergeladen für {0}",
     "SubtitlesDownloadedForItem": "Untertitel heruntergeladen für {0}",
     "Sync": "Synchronisation",
     "Sync": "Synchronisation",
     "System": "System",
     "System": "System",
-    "TvShows": "TV Sendungen",
+    "TvShows": "TV-Sendungen",
     "User": "Benutzer",
     "User": "Benutzer",
     "UserCreatedWithName": "Benutzer {0} wurde erstellt",
     "UserCreatedWithName": "Benutzer {0} wurde erstellt",
     "UserDeletedWithName": "Benutzer {0} wurde gelöscht",
     "UserDeletedWithName": "Benutzer {0} wurde gelöscht",
@@ -88,10 +88,10 @@
     "UserOfflineFromDevice": "{0} wurde getrennt von {1}",
     "UserOfflineFromDevice": "{0} wurde getrennt von {1}",
     "UserOnlineFromDevice": "{0} ist online von {1}",
     "UserOnlineFromDevice": "{0} ist online von {1}",
     "UserPasswordChangedWithName": "Das Passwort für Benutzer {0} wurde geändert",
     "UserPasswordChangedWithName": "Das Passwort für Benutzer {0} wurde geändert",
-    "UserPolicyUpdatedWithName": "Benutzerrichtlinie wurde für {0} aktualisiert",
-    "UserStartedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} gestartet",
-    "UserStoppedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} beendet",
-    "ValueHasBeenAddedToLibrary": "{0} wurde ihrer Bibliothek hinzugefügt",
-    "ValueSpecialEpisodeName": "Special - {0}",
+    "UserPolicyUpdatedWithName": "Benutzerrichtlinie von {0} wurde aktualisiert",
+    "UserStartedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} auf {2} gestartet",
+    "UserStoppedPlayingItemWithValues": "{0} hat die Wiedergabe von {1} auf {2} beendet",
+    "ValueHasBeenAddedToLibrary": "{0} wurde deiner Bibliothek hinzugefügt",
+    "ValueSpecialEpisodeName": "Extra - {0}",
     "VersionNumber": "Version {0}"
     "VersionNumber": "Version {0}"
 }
 }

+ 1 - 1
Emby.Server.Implementations/Localization/Core/en-GB.json

@@ -90,7 +90,7 @@
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
     "UserPasswordChangedWithName": "Password has been changed for user {0}",
     "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
     "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
     "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
     "UserStartedPlayingItemWithValues": "{0} has started playing {1}",
-    "UserStoppedPlayingItemWithValues": "{0} has stopped playing {1}",
+    "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
     "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
     "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
     "ValueSpecialEpisodeName": "Special - {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
     "VersionNumber": "Version {0}"
     "VersionNumber": "Version {0}"

+ 1 - 1
Emby.Server.Implementations/Localization/Core/en-US.json

@@ -30,7 +30,7 @@
     "Inherit": "Inherit",
     "Inherit": "Inherit",
     "ItemAddedWithName": "{0} was added to the library",
     "ItemAddedWithName": "{0} was added to the library",
     "ItemRemovedWithName": "{0} was removed from the library",
     "ItemRemovedWithName": "{0} was removed from the library",
-    "LabelIpAddressValue": "Ip address: {0}",
+    "LabelIpAddressValue": "IP address: {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "LabelRunningTimeValue": "Running time: {0}",
     "Latest": "Latest",
     "Latest": "Latest",
     "MessageApplicationUpdated": "Jellyfin Server has been updated",
     "MessageApplicationUpdated": "Jellyfin Server has been updated",

+ 23 - 23
Emby.Server.Implementations/Localization/Core/es.json

@@ -5,46 +5,46 @@
     "Artists": "Artistas",
     "Artists": "Artistas",
     "AuthenticationSucceededWithUserName": "{0} autenticado correctamente",
     "AuthenticationSucceededWithUserName": "{0} autenticado correctamente",
     "Books": "Libros",
     "Books": "Libros",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "Se ha subido una nueva imagen de cámara desde {0}",
     "Channels": "Canales",
     "Channels": "Canales",
     "ChapterNameValue": "Capítulo {0}",
     "ChapterNameValue": "Capítulo {0}",
     "Collections": "Colecciones",
     "Collections": "Colecciones",
     "DeviceOfflineWithName": "{0} se ha desconectado",
     "DeviceOfflineWithName": "{0} se ha desconectado",
     "DeviceOnlineWithName": "{0} está conectado",
     "DeviceOnlineWithName": "{0} está conectado",
-    "FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión a partir de {0}",
+    "FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión desde {0}",
     "Favorites": "Favoritos",
     "Favorites": "Favoritos",
     "Folders": "Carpetas",
     "Folders": "Carpetas",
     "Genres": "Géneros",
     "Genres": "Géneros",
-    "HeaderAlbumArtists": "Artistas del Álbum",
-    "HeaderCameraUploads": "Camera Uploads",
+    "HeaderAlbumArtists": "Artistas del álbum",
+    "HeaderCameraUploads": "Subidas desde cámara",
     "HeaderContinueWatching": "Continuar viendo",
     "HeaderContinueWatching": "Continuar viendo",
     "HeaderFavoriteAlbums": "Álbumes favoritos",
     "HeaderFavoriteAlbums": "Álbumes favoritos",
     "HeaderFavoriteArtists": "Artistas favoritos",
     "HeaderFavoriteArtists": "Artistas favoritos",
     "HeaderFavoriteEpisodes": "Episodios favoritos",
     "HeaderFavoriteEpisodes": "Episodios favoritos",
     "HeaderFavoriteShows": "Programas favoritos",
     "HeaderFavoriteShows": "Programas favoritos",
     "HeaderFavoriteSongs": "Canciones favoritas",
     "HeaderFavoriteSongs": "Canciones favoritas",
-    "HeaderLiveTV": "TV en vivo",
+    "HeaderLiveTV": "TV en directo",
     "HeaderNextUp": "Siguiendo",
     "HeaderNextUp": "Siguiendo",
     "HeaderRecordingGroups": "Grupos de grabación",
     "HeaderRecordingGroups": "Grupos de grabación",
-    "HomeVideos": "Vídeos de inicio",
+    "HomeVideos": "Vídeos caseros",
     "Inherit": "Heredar",
     "Inherit": "Heredar",
     "ItemAddedWithName": "{0} se ha añadido a la biblioteca",
     "ItemAddedWithName": "{0} se ha añadido a la biblioteca",
-    "ItemRemovedWithName": "{0} se elimina de la biblioteca",
+    "ItemRemovedWithName": "{0} ha sido eliminado de la biblioteca",
     "LabelIpAddressValue": "Dirección IP: {0}",
     "LabelIpAddressValue": "Dirección IP: {0}",
     "LabelRunningTimeValue": "Tiempo de funcionamiento: {0}",
     "LabelRunningTimeValue": "Tiempo de funcionamiento: {0}",
     "Latest": "Últimos",
     "Latest": "Últimos",
     "MessageApplicationUpdated": "Se ha actualizado el servidor Jellyfin",
     "MessageApplicationUpdated": "Se ha actualizado el servidor Jellyfin",
-    "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
-    "MessageNamedServerConfigurationUpdatedWithValue": "La sección de configuración del servidor {0} ha sido actualizado",
+    "MessageApplicationUpdatedTo": "Se ha actualizado el servidor Jellyfin a la versión {0}",
+    "MessageNamedServerConfigurationUpdatedWithValue": "La sección {0} de configuración del servidor ha sido actualizada",
     "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
     "MessageServerConfigurationUpdated": "Se ha actualizado la configuración del servidor",
     "MixedContent": "Contenido mixto",
     "MixedContent": "Contenido mixto",
-    "Movies": "Peliculas",
+    "Movies": "Películas",
     "Music": "Música",
     "Music": "Música",
-    "MusicVideos": "Videos musicales",
-    "NameInstallFailed": "{0} installation failed",
+    "MusicVideos": "Vídeos musicales",
+    "NameInstallFailed": "{0} error de instalación",
     "NameSeasonNumber": "Temporada {0}",
     "NameSeasonNumber": "Temporada {0}",
-    "NameSeasonUnknown": "Season Unknown",
-    "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
+    "NameSeasonUnknown": "Temporada desconocida",
+    "NewVersionIsAvailable": "Disponible una nueva versión de Jellyfin para descargar.",
     "NotificationOptionApplicationUpdateAvailable": "Actualización de la aplicación disponible",
     "NotificationOptionApplicationUpdateAvailable": "Actualización de la aplicación disponible",
     "NotificationOptionApplicationUpdateInstalled": "Actualización de la aplicación instalada",
     "NotificationOptionApplicationUpdateInstalled": "Actualización de la aplicación instalada",
     "NotificationOptionAudioPlayback": "Se inició la reproducción de audio",
     "NotificationOptionAudioPlayback": "Se inició la reproducción de audio",
@@ -56,13 +56,13 @@
     "NotificationOptionPluginInstalled": "Plugin instalado",
     "NotificationOptionPluginInstalled": "Plugin instalado",
     "NotificationOptionPluginUninstalled": "Plugin desinstalado",
     "NotificationOptionPluginUninstalled": "Plugin desinstalado",
     "NotificationOptionPluginUpdateInstalled": "Actualización del complemento instalada",
     "NotificationOptionPluginUpdateInstalled": "Actualización del complemento instalada",
-    "NotificationOptionServerRestartRequired": "Requiere reinicio del servidor",
+    "NotificationOptionServerRestartRequired": "Se requiere reinicio del servidor",
     "NotificationOptionTaskFailed": "Error de tarea programada",
     "NotificationOptionTaskFailed": "Error de tarea programada",
     "NotificationOptionUserLockedOut": "Usuario bloqueado",
     "NotificationOptionUserLockedOut": "Usuario bloqueado",
     "NotificationOptionVideoPlayback": "Se inició la reproducción de vídeo",
     "NotificationOptionVideoPlayback": "Se inició la reproducción de vídeo",
     "NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo detenida",
     "NotificationOptionVideoPlaybackStopped": "Reproducción de vídeo detenida",
     "Photos": "Fotos",
     "Photos": "Fotos",
-    "Playlists": "Listas reproducción",
+    "Playlists": "Listas de reproducción",
     "Plugin": "Plugin",
     "Plugin": "Plugin",
     "PluginInstalledWithName": "{0} se ha instalado",
     "PluginInstalledWithName": "{0} se ha instalado",
     "PluginUninstalledWithName": "{0} se ha desinstalado",
     "PluginUninstalledWithName": "{0} se ha desinstalado",
@@ -70,16 +70,16 @@
     "ProviderValue": "Proveedor: {0}",
     "ProviderValue": "Proveedor: {0}",
     "ScheduledTaskFailedWithName": "{0} falló",
     "ScheduledTaskFailedWithName": "{0} falló",
     "ScheduledTaskStartedWithName": "{0} iniciada",
     "ScheduledTaskStartedWithName": "{0} iniciada",
-    "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
+    "ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado",
     "Shows": "Series",
     "Shows": "Series",
     "Songs": "Canciones",
     "Songs": "Canciones",
     "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
     "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.",
     "SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
     "SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}",
     "SubtitlesDownloadedForItem": "Descargar subtítulos para {0}",
     "SubtitlesDownloadedForItem": "Descargar subtítulos para {0}",
     "Sync": "Sincronizar",
     "Sync": "Sincronizar",
     "System": "Sistema",
     "System": "Sistema",
-    "TvShows": "Series TV",
+    "TvShows": "Series de TV",
     "User": "Usuario",
     "User": "Usuario",
     "UserCreatedWithName": "El usuario {0} ha sido creado",
     "UserCreatedWithName": "El usuario {0} ha sido creado",
     "UserDeletedWithName": "El usuario {0} ha sido borrado",
     "UserDeletedWithName": "El usuario {0} ha sido borrado",
@@ -88,10 +88,10 @@
     "UserOfflineFromDevice": "{0} se ha desconectado de {1}",
     "UserOfflineFromDevice": "{0} se ha desconectado de {1}",
     "UserOnlineFromDevice": "{0} está en línea desde {1}",
     "UserOnlineFromDevice": "{0} está en línea desde {1}",
     "UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
     "UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}",
-    "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
-    "UserStartedPlayingItemWithValues": "{0} ha comenzado reproducir {1}",
-    "UserStoppedPlayingItemWithValues": "{0} ha parado de reproducir {1}",
-    "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+    "UserPolicyUpdatedWithName": "Actualizada política de usuario para {0}",
+    "UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}",
+    "UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}",
+    "ValueHasBeenAddedToLibrary": "{0} ha sido añadido a tu biblioteca multimedia",
     "ValueSpecialEpisodeName": "Especial - {0}",
     "ValueSpecialEpisodeName": "Especial - {0}",
     "VersionNumber": "Versión {0}"
     "VersionNumber": "Versión {0}"
 }
 }

+ 1 - 1
Emby.Server.Implementations/Localization/Core/fr.json

@@ -36,7 +36,7 @@
     "MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
     "MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour",
     "MessageApplicationUpdatedTo": "Jellyfin Serveur a été mis à jour en version {0}",
     "MessageApplicationUpdatedTo": "Jellyfin Serveur a été mis à jour en version {0}",
     "MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
     "MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour",
-    "MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour.",
+    "MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour",
     "MixedContent": "Contenu mixte",
     "MixedContent": "Contenu mixte",
     "Movies": "Films",
     "Movies": "Films",
     "Music": "Musique",
     "Music": "Musique",

+ 35 - 35
Emby.Server.Implementations/Localization/Core/hu.json

@@ -5,48 +5,48 @@
     "Artists": "Előadók",
     "Artists": "Előadók",
     "AuthenticationSucceededWithUserName": "{0} sikeresen azonosítva",
     "AuthenticationSucceededWithUserName": "{0} sikeresen azonosítva",
     "Books": "Könyvek",
     "Books": "Könyvek",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "Új kamerakép került feltöltésre {0}",
     "Channels": "Csatornák",
     "Channels": "Csatornák",
     "ChapterNameValue": "Jelenet {0}",
     "ChapterNameValue": "Jelenet {0}",
     "Collections": "Gyűjtemények",
     "Collections": "Gyűjtemények",
     "DeviceOfflineWithName": "{0} kijelentkezett",
     "DeviceOfflineWithName": "{0} kijelentkezett",
     "DeviceOnlineWithName": "{0} belépett",
     "DeviceOnlineWithName": "{0} belépett",
-    "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
+    "FailedLoginAttemptWithUserName": "Sikertelen bejelentkezési kísérlet {0}",
     "Favorites": "Kedvencek",
     "Favorites": "Kedvencek",
     "Folders": "Könyvtárak",
     "Folders": "Könyvtárak",
     "Genres": "Műfajok",
     "Genres": "Műfajok",
     "HeaderAlbumArtists": "Album Előadók",
     "HeaderAlbumArtists": "Album Előadók",
-    "HeaderCameraUploads": "Camera Uploads",
-    "HeaderContinueWatching": "Vetítés(ek) folytatása",
+    "HeaderCameraUploads": "Kamera feltöltések",
+    "HeaderContinueWatching": "Folyamatban lévő filmek",
     "HeaderFavoriteAlbums": "Kedvenc Albumok",
     "HeaderFavoriteAlbums": "Kedvenc Albumok",
     "HeaderFavoriteArtists": "Kedvenc Művészek",
     "HeaderFavoriteArtists": "Kedvenc Művészek",
     "HeaderFavoriteEpisodes": "Kedvenc Epizódok",
     "HeaderFavoriteEpisodes": "Kedvenc Epizódok",
     "HeaderFavoriteShows": "Kedvenc Műsorok",
     "HeaderFavoriteShows": "Kedvenc Műsorok",
     "HeaderFavoriteSongs": "Kedvenc Dalok",
     "HeaderFavoriteSongs": "Kedvenc Dalok",
-    "HeaderLiveTV": "Live TV",
+    "HeaderLiveTV": "Élő TV",
     "HeaderNextUp": "Következik",
     "HeaderNextUp": "Következik",
-    "HeaderRecordingGroups": "Recording Groups",
+    "HeaderRecordingGroups": "Felvételi csoportok",
     "HomeVideos": "Házi videók",
     "HomeVideos": "Házi videók",
     "Inherit": "Inherit",
     "Inherit": "Inherit",
-    "ItemAddedWithName": "{0} was added to the library",
-    "ItemRemovedWithName": "{0} was removed from the library",
-    "LabelIpAddressValue": "Ip cím: {0}",
-    "LabelRunningTimeValue": "Running time: {0}",
+    "ItemAddedWithName": "{0} hozzáadva a könyvtárhoz",
+    "ItemRemovedWithName": "{0} eltávolítva a könyvtárból",
+    "LabelIpAddressValue": "IP cím: {0}",
+    "LabelRunningTimeValue": "Futási idő: {0}",
     "Latest": "Legújabb",
     "Latest": "Legújabb",
     "MessageApplicationUpdated": "Jellyfin Szerver frissítve",
     "MessageApplicationUpdated": "Jellyfin Szerver frissítve",
-    "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
+    "MessageApplicationUpdatedTo": "Jellyfin Szerver frissítve lett a következőre {0}",
     "MessageNamedServerConfigurationUpdatedWithValue": "Szerver konfigurációs rész {0} frissítve",
     "MessageNamedServerConfigurationUpdatedWithValue": "Szerver konfigurációs rész {0} frissítve",
     "MessageServerConfigurationUpdated": "Szerver konfiguráció frissítve",
     "MessageServerConfigurationUpdated": "Szerver konfiguráció frissítve",
     "MixedContent": "Vegyes tartalom",
     "MixedContent": "Vegyes tartalom",
     "Movies": "Filmek",
     "Movies": "Filmek",
     "Music": "Zene",
     "Music": "Zene",
     "MusicVideos": "Zenei Videók",
     "MusicVideos": "Zenei Videók",
-    "NameInstallFailed": "{0} installation failed",
-    "NameSeasonNumber": "Season {0}",
-    "NameSeasonUnknown": "Season Unknown",
-    "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
-    "NotificationOptionApplicationUpdateAvailable": "Program frissítés elérhető",
-    "NotificationOptionApplicationUpdateInstalled": "Program frissítés telepítve",
+    "NameInstallFailed": "{0} sikertelen telepítés",
+    "NameSeasonNumber": "Évad {0}",
+    "NameSeasonUnknown": "Ismeretlen évad",
+    "NewVersionIsAvailable": "Letölthető a Jellyfin Szerver új verziója.",
+    "NotificationOptionApplicationUpdateAvailable": "Új programfrissítés érhető el",
+    "NotificationOptionApplicationUpdateInstalled": "Programfrissítés telepítve",
     "NotificationOptionAudioPlayback": "Audió lejátszás elkezdve",
     "NotificationOptionAudioPlayback": "Audió lejátszás elkezdve",
     "NotificationOptionAudioPlaybackStopped": "Audió lejátszás befejezve",
     "NotificationOptionAudioPlaybackStopped": "Audió lejátszás befejezve",
     "NotificationOptionCameraImageUploaded": "Kamera kép feltöltve",
     "NotificationOptionCameraImageUploaded": "Kamera kép feltöltve",
@@ -57,7 +57,7 @@
     "NotificationOptionPluginUninstalled": "Bővítmény eltávolítva",
     "NotificationOptionPluginUninstalled": "Bővítmény eltávolítva",
     "NotificationOptionPluginUpdateInstalled": "Bővítmény frissítés telepítve",
     "NotificationOptionPluginUpdateInstalled": "Bővítmény frissítés telepítve",
     "NotificationOptionServerRestartRequired": "Szerver újraindítás szükséges",
     "NotificationOptionServerRestartRequired": "Szerver újraindítás szükséges",
-    "NotificationOptionTaskFailed": "Scheduled task failure",
+    "NotificationOptionTaskFailed": "Ütemezett feladat hiba",
     "NotificationOptionUserLockedOut": "Felhasználó tiltva",
     "NotificationOptionUserLockedOut": "Felhasználó tiltva",
     "NotificationOptionVideoPlayback": "Videó lejátszás elkezdve",
     "NotificationOptionVideoPlayback": "Videó lejátszás elkezdve",
     "NotificationOptionVideoPlaybackStopped": "Videó lejátszás befejezve",
     "NotificationOptionVideoPlaybackStopped": "Videó lejátszás befejezve",
@@ -68,30 +68,30 @@
     "PluginUninstalledWithName": "{0} eltávolítva",
     "PluginUninstalledWithName": "{0} eltávolítva",
     "PluginUpdatedWithName": "{0} frissítve",
     "PluginUpdatedWithName": "{0} frissítve",
     "ProviderValue": "Provider: {0}",
     "ProviderValue": "Provider: {0}",
-    "ScheduledTaskFailedWithName": "{0} failed",
-    "ScheduledTaskStartedWithName": "{0} started",
-    "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
+    "ScheduledTaskFailedWithName": "{0} hiba",
+    "ScheduledTaskStartedWithName": "{0} elkezdve",
+    "ServerNameNeedsToBeRestarted": "{0}-t újra kell indítani",
     "Shows": "Műsorok",
     "Shows": "Műsorok",
     "Songs": "Dalok",
     "Songs": "Dalok",
-    "StartupEmbyServerIsLoading": "Jellyfin Szerver betöltődik. Kérjük, próbáld meg újra később.",
+    "StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek próbáld újra később.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
+    "SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen:  {0} ehhez: {1}",
+    "SubtitlesDownloadedForItem": "Letöltött feliratok a következőhöz {0}",
     "Sync": "Szinkronizál",
     "Sync": "Szinkronizál",
     "System": "Rendszer",
     "System": "Rendszer",
     "TvShows": "TV Műsorok",
     "TvShows": "TV Műsorok",
     "User": "Felhasználó",
     "User": "Felhasználó",
-    "UserCreatedWithName": "User {0} has been created",
-    "UserDeletedWithName": "User {0} has been deleted",
+    "UserCreatedWithName": "{0} felhasználó létrehozva",
+    "UserDeletedWithName": "{0} felhasználó törölve",
     "UserDownloadingItemWithValues": "{0} letölti {1}",
     "UserDownloadingItemWithValues": "{0} letölti {1}",
-    "UserLockedOutWithName": "User {0} has been locked out",
-    "UserOfflineFromDevice": "{0} kijelentkezett innen  {1}",
-    "UserOnlineFromDevice": "{0} is online from {1}",
-    "UserPasswordChangedWithName": "Password has been changed for user {0}",
-    "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
-    "UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt {1}",
-    "UserStoppedPlayingItemWithValues": "{0} befejezte a következőt {1}",
-    "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+    "UserLockedOutWithName": "{0}  felhasználó zárolva van",
+    "UserOfflineFromDevice": "{0} kijelentkezett innen:  {1}",
+    "UserOnlineFromDevice": "{0} online itt:  {1}",
+    "UserPasswordChangedWithName": "Jelszó megváltozott a következő felhasználó számára: {0}",
+    "UserPolicyUpdatedWithName": "A felhasználói házirend frissítve lett {0}",
+    "UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt: {1} itt:  {2}",
+    "UserStoppedPlayingItemWithValues": "{0} befejezte a következőt: {1} itt:  {2}",
+    "ValueHasBeenAddedToLibrary": "{0} hozzáadva a médiatárhoz",
     "ValueSpecialEpisodeName": "Special - {0}",
     "ValueSpecialEpisodeName": "Special - {0}",
-    "VersionNumber": "Verzió {0}"
+    "VersionNumber": "Verzió: {0}"
 }
 }

+ 4 - 4
Emby.Server.Implementations/Localization/Core/it.json

@@ -5,13 +5,13 @@
     "Artists": "Artisti",
     "Artists": "Artisti",
     "AuthenticationSucceededWithUserName": "{0} autenticato con successo",
     "AuthenticationSucceededWithUserName": "{0} autenticato con successo",
     "Books": "Libri",
     "Books": "Libri",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "È stata caricata una nuova immagine della fotocamera {0}",
     "Channels": "Canali",
     "Channels": "Canali",
     "ChapterNameValue": "Capitolo {0}",
     "ChapterNameValue": "Capitolo {0}",
     "Collections": "Collezioni",
     "Collections": "Collezioni",
     "DeviceOfflineWithName": "{0} è stato disconnesso",
     "DeviceOfflineWithName": "{0} è stato disconnesso",
     "DeviceOnlineWithName": "{0} è connesso",
     "DeviceOnlineWithName": "{0} è connesso",
-    "FailedLoginAttemptWithUserName": "Tentativo di accesso fallito da  {0}",
+    "FailedLoginAttemptWithUserName": "Tentativo di accesso fallito da {0}",
     "Favorites": "Preferiti",
     "Favorites": "Preferiti",
     "Folders": "Cartelle",
     "Folders": "Cartelle",
     "Genres": "Generi",
     "Genres": "Generi",
@@ -19,9 +19,9 @@
     "HeaderCameraUploads": "Caricamenti Fotocamera",
     "HeaderCameraUploads": "Caricamenti Fotocamera",
     "HeaderContinueWatching": "Continua a guardare",
     "HeaderContinueWatching": "Continua a guardare",
     "HeaderFavoriteAlbums": "Album preferiti",
     "HeaderFavoriteAlbums": "Album preferiti",
-    "HeaderFavoriteArtists": "Artisti preferiti",
+    "HeaderFavoriteArtists": "Artisti Preferiti",
     "HeaderFavoriteEpisodes": "Episodi Preferiti",
     "HeaderFavoriteEpisodes": "Episodi Preferiti",
-    "HeaderFavoriteShows": "Show preferiti",
+    "HeaderFavoriteShows": "Serie TV Preferite",
     "HeaderFavoriteSongs": "Brani Preferiti",
     "HeaderFavoriteSongs": "Brani Preferiti",
     "HeaderLiveTV": "Diretta TV",
     "HeaderLiveTV": "Diretta TV",
     "HeaderNextUp": "Prossimo",
     "HeaderNextUp": "Prossimo",

+ 94 - 94
Emby.Server.Implementations/Localization/Core/kk.json

@@ -1,97 +1,97 @@
 {
 {
-    "Albums": "Альбомдар",
-    "AppDeviceValues": "Қолданба: {0}, Құрылғы: {1}",
-    "Application": "Қолданба",
-    "Artists": "Орындаушылар",
-    "AuthenticationSucceededWithUserName": "{0} түпнұсқалығын расталуы сәтті",
-    "Books": "Кітаптар",
-    "CameraImageUploadedFrom": "Жаңа сурет {0} камерасынан жүктеп алынды",
-    "Channels": "Арналар",
-    "ChapterNameValue": "{0}-сахна",
-    "Collections": "Жиынтықтар",
-    "DeviceOfflineWithName": "{0} ажыратылған",
-    "DeviceOnlineWithName": "{0} қосылған",
-    "FailedLoginAttemptWithUserName": "{0} тарапынан кіру әрекеті сәтсіз",
-    "Favorites": "Таңдаулылар",
-    "Folders": "Қалталар",
-    "Genres": "Жанрлар",
-    "HeaderAlbumArtists": "Альбом орындаушылары",
-    "HeaderCameraUploads": "Камерадан жүктелгендер",
-    "HeaderContinueWatching": "Қарауды жалғастыру",
-    "HeaderFavoriteAlbums": "Таңдаулы альбомдар",
-    "HeaderFavoriteArtists": "Таңдаулы орындаушылар",
-    "HeaderFavoriteEpisodes": "Таңдаулы бөлімдер",
-    "HeaderFavoriteShows": "Таңдаулы көрсетімдер",
-    "HeaderFavoriteSongs": "Таңдаулы әуендер",
-    "HeaderLiveTV": "Эфир",
-    "HeaderNextUp": "Кезекті",
-    "HeaderRecordingGroups": "Жазба топтары",
-    "HomeVideos": "Үйлік бейнелер",
-    "Inherit": "Мұраға иелену",
-    "ItemAddedWithName": "{0} тасығышханаға үстелінді",
-    "ItemRemovedWithName": "{0} тасығышханадан аласталды",
-    "LabelIpAddressValue": "IP-мекенжайы: {0}",
-    "LabelRunningTimeValue": "Іске қосылу уақыты: {0}",
-    "Latest": "Ең кейінгі",
-    "MessageApplicationUpdated": "Jellyfin Server жаңартылды.",
-    "MessageApplicationUpdatedTo": "Jellyfin Server {0} үшін жаңартылды",
-    "MessageNamedServerConfigurationUpdatedWithValue": "Сервер теңшелімі ({0} бөлімі) жаңартылды",
-    "MessageServerConfigurationUpdated": "Сервер теңшелімі жаңартылды",
-    "MixedContent": "Аралас мазмұн",
-    "Movies": "Фильмдер",
-    "Music": "Музыка",
-    "MusicVideos": "Музыкалық бейнелер",
-    "NameInstallFailed": "{0} орнатылуы сәтсіз",
-    "NameSeasonNumber": "{0}-маусым",
-    "NameSeasonUnknown": "Белгісіз маусым",
-    "NewVersionIsAvailable": "Жаңа Jellyfin Server нұсқасы жүктеп алуға қолжетімді.",
-    "NotificationOptionApplicationUpdateAvailable": "Қолданба жаңартуы қолжетімді",
-    "NotificationOptionApplicationUpdateInstalled": "Қолданба жаңартуы орнатылды",
-    "NotificationOptionAudioPlayback": "Дыбыс ойнатуы басталды",
-    "NotificationOptionAudioPlaybackStopped": "Дыбыс ойнатуы тоқтатылды",
-    "NotificationOptionCameraImageUploaded": "Камерадан фотосурет кері қотарылған",
-    "NotificationOptionInstallationFailed": "Орнату сәтсіздігі",
-    "NotificationOptionNewLibraryContent": "Жаңа мазмұн үстелген",
-    "NotificationOptionPluginError": "Плагин сәтсіздігі",
-    "NotificationOptionPluginInstalled": "Плагин орнатылды",
-    "NotificationOptionPluginUninstalled": "Плагин орнатуы болдырылмады",
-    "NotificationOptionPluginUpdateInstalled": "Плагин жаңартуы орнатылды",
-    "NotificationOptionServerRestartRequired": "Серверді қайта іске қосу қажет",
-    "NotificationOptionTaskFailed": "Жоспарлаған тапсырма сәтсіздігі",
-    "NotificationOptionUserLockedOut": "Пайдаланушы құрсаулы",
-    "NotificationOptionVideoPlayback": "Бейне ойнатуы басталды",
-    "NotificationOptionVideoPlaybackStopped": "Бейне ойнатуы тоқтатылды",
-    "Photos": "Фотосуреттер",
-    "Playlists": "Ойнату тізімдері",
-    "Plugin": "Плагин",
-    "PluginInstalledWithName": "{0} орнатылды",
-    "PluginUninstalledWithName": "{0} жойылды",
-    "PluginUpdatedWithName": "{0} жаңартылды",
-    "ProviderValue": "Жеткізуші: {0}",
-    "ScheduledTaskFailedWithName": "{0} сәтсіз",
-    "ScheduledTaskStartedWithName": "{0} іске қосылды",
-    "ServerNameNeedsToBeRestarted": "{0} қайта іске қосу қажет",
-    "Shows": "Көрсетімдер",
-    "Songs": "Әуендер",
-    "StartupEmbyServerIsLoading": "Jellyfin Server жүктелуде. Әрекетті көп ұзамай қайталаңыз.",
+    "Albums": "Álbomdar",
+    "AppDeviceValues": "Qoldanba: {0}, Qurylǵy: {1}",
+    "Application": "Qoldanba",
+    "Artists": "Oryndaýshylar",
+    "AuthenticationSucceededWithUserName": "{0} túpnusqalyǵyn rastalýy sátti",
+    "Books": "Kitaptar",
+    "CameraImageUploadedFrom": "Jańa sýret {0} kamerasynan júktep alyndy",
+    "Channels": "Arnalar",
+    "ChapterNameValue": "{0}-sahna",
+    "Collections": "Jıyntyqtar",
+    "DeviceOfflineWithName": "{0} ajyratylǵan",
+    "DeviceOnlineWithName": "{0} qosylǵan",
+    "FailedLoginAttemptWithUserName": "{0} tarapynan kirý áreketi sátsiz",
+    "Favorites": "Tańdaýlylar",
+    "Folders": "Qaltalar",
+    "Genres": "Janrlar",
+    "HeaderAlbumArtists": "Álbom oryndaýshylary",
+    "HeaderCameraUploads": "Kameradan júktelgender",
+    "HeaderContinueWatching": "Qaraýdy jalǵastyrý",
+    "HeaderFavoriteAlbums": "Tańdaýly álbomdar",
+    "HeaderFavoriteArtists": "Tańdaýly oryndaýshylar",
+    "HeaderFavoriteEpisodes": "Tańdaýly bólimder",
+    "HeaderFavoriteShows": "Tańdaýly kórsetimder",
+    "HeaderFavoriteSongs": "Tańdaýly áýender",
+    "HeaderLiveTV": "Efır",
+    "HeaderNextUp": "Kezekti",
+    "HeaderRecordingGroups": "Jazba toptary",
+    "HomeVideos": "Úılik beıneler",
+    "Inherit": "Muraǵa ıelený",
+    "ItemAddedWithName": "{0} tasyǵyshhanaǵa ústelindi",
+    "ItemRemovedWithName": "{0} tasyǵyshhanadan alastaldy",
+    "LabelIpAddressValue": "IP-mekenjaıy: {0}",
+    "LabelRunningTimeValue": "Oınatý ýaqyty: {0}",
+    "Latest": "Eń keıingi",
+    "MessageApplicationUpdated": "Jellyfin Serveri jańartyldy",
+    "MessageApplicationUpdatedTo": "Jellyfin Serveri {0} deńgeıge jańartyldy",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Server teńsheliminiń {0} bólimi jańartyldy",
+    "MessageServerConfigurationUpdated": "Server teńshelimi jańartyldy",
+    "MixedContent": "Aralas mazmun",
+    "Movies": "Fılmder",
+    "Music": "Mýzyka",
+    "MusicVideos": "Mýzykalyq beıneler",
+    "NameInstallFailed": "{0} ornatylýy sátsiz",
+    "NameSeasonNumber": "{0}-maýsym",
+    "NameSeasonUnknown": "Belgisiz maýsym",
+    "NewVersionIsAvailable": "Jańa Jellyfin Server nusqasy júktep alýǵa qoljetimdi.",
+    "NotificationOptionApplicationUpdateAvailable": "Qoldanba jańartýy qoljetimdi",
+    "NotificationOptionApplicationUpdateInstalled": "Qoldanba jańartýy ornatyldy",
+    "NotificationOptionAudioPlayback": "Dybys oınatýy bastaldy",
+    "NotificationOptionAudioPlaybackStopped": "Dybys oınatýy toqtatyldy",
+    "NotificationOptionCameraImageUploaded": "Kameradan fotosýret keri qotarylǵan",
+    "NotificationOptionInstallationFailed": "Ornatý sátsizdigi",
+    "NotificationOptionNewLibraryContent": "Jańa mazmun ústelgen",
+    "NotificationOptionPluginError": "Plagın sátsizdigi",
+    "NotificationOptionPluginInstalled": "Plagın ornatyldy",
+    "NotificationOptionPluginUninstalled": "Plagın ornatýy boldyrylmady",
+    "NotificationOptionPluginUpdateInstalled": "Plagın jańartýy ornatyldy",
+    "NotificationOptionServerRestartRequired": "Serverdi qaıta iske qosý qajet",
+    "NotificationOptionTaskFailed": "Josparlaǵan tapsyrma sátsizdigi",
+    "NotificationOptionUserLockedOut": "Paıdalanýshy qursaýly",
+    "NotificationOptionVideoPlayback": "Beıne oınatýy bastaldy",
+    "NotificationOptionVideoPlaybackStopped": "Beıne oınatýy toqtatyldy",
+    "Photos": "Fotosýretter",
+    "Playlists": "Oınatý tizimderi",
+    "Plugin": "Plagın",
+    "PluginInstalledWithName": "{0} ornatyldy",
+    "PluginUninstalledWithName": "{0} joıyldy",
+    "PluginUpdatedWithName": "{0} jańartyldy",
+    "ProviderValue": "Jetkizýshi: {0}",
+    "ScheduledTaskFailedWithName": "{0} sátsiz",
+    "ScheduledTaskStartedWithName": "{0} iske qosyldy",
+    "ServerNameNeedsToBeRestarted": "{0} qaıta iske qosý qajet",
+    "Shows": "Kórsetimder",
+    "Songs": "Áýender",
+    "StartupEmbyServerIsLoading": "Jellyfin Server júktelýde. Áreketti kóp uzamaı qaıtalańyz.",
     "SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
     "SubtitleDownloadFailureForItem": "Субтитрлер {0} үшін жүктеліп алынуы сәтсіз",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "{0} үшін субтитрлер жүктеліп алынды",
-    "Sync": "Үндестіру",
-    "System": "Жүйе",
-    "TvShows": "ТД-көрсетімдер",
-    "User": "Пайдаланушы",
-    "UserCreatedWithName": "Пайдаланушы {0} жасалған",
-    "UserDeletedWithName": "Пайдаланушы {0} жойылған",
-    "UserDownloadingItemWithValues": "{0} мынаны жүктеп алуда: {1}",
-    "UserLockedOutWithName": "Пайдаланушы {0} құрсаулы",
-    "UserOfflineFromDevice": "{0} - {1} тарапынан ажыратылған",
-    "UserOnlineFromDevice": "{0} - {1} арқылы қосылған",
-    "UserPasswordChangedWithName": "Пайдаланушы {0} үшін құпия сөз өзгертілді",
-    "UserPolicyUpdatedWithName": "Пайдаланушы {0} үшін саясаттары жаңартылды",
-    "UserStartedPlayingItemWithValues": "{0} - {1} ойнатуын  {2} бастады",
-    "UserStoppedPlayingItemWithValues": "{0} - {1} ойнатуын  {2} тоқтатты",
-    "ValueHasBeenAddedToLibrary": "{0} (тасығышханаға үстелінді)",
-    "ValueSpecialEpisodeName": "Арнайы - {0}",
-    "VersionNumber": "Нұсқасы: {0}"
+    "SubtitleDownloadFailureFromForItem": "{1} úshin sýbtıtrlerdi {0} kózinen júktep alý sátsiz",
+    "SubtitlesDownloadedForItem": "{0} úshin sýbtıtrler júktelip alyndy",
+    "Sync": "Úndestirý",
+    "System": "Júıe",
+    "TvShows": "TD-kórsetimder",
+    "User": "Paıdalanýshy",
+    "UserCreatedWithName": "Paıdalanýshy {0} jasalǵan",
+    "UserDeletedWithName": "Paıdalanýshy {0} joıylǵan",
+    "UserDownloadingItemWithValues": "{0} mynany júktep alýda: {1}",
+    "UserLockedOutWithName": "Paıdalanýshy {0} qursaýly",
+    "UserOfflineFromDevice": "{0} - {1} tarapynan ajyratylǵan",
+    "UserOnlineFromDevice": "{0} - {1} arqyly qosylǵan",
+    "UserPasswordChangedWithName": "Paıdalanýshy {0} úshin paról ózgertildi",
+    "UserPolicyUpdatedWithName": "Paıdalanýshy {0} úshin saıasattary jańartyldy",
+    "UserStartedPlayingItemWithValues": "{0} - {1} oınatýyn {2} bastady",
+    "UserStoppedPlayingItemWithValues": "{0} - {1} oınatýyn {2} toqtatty",
+    "ValueHasBeenAddedToLibrary": "{0} (tasyǵyshhanaǵa ústelindi)",
+    "ValueSpecialEpisodeName": "Arnaıy - {0}",
+    "VersionNumber": "Nusqasy {0}"
 }
 }

+ 3 - 3
Emby.Server.Implementations/Localization/Core/ms.json

@@ -1,10 +1,10 @@
 {
 {
-    "Albums": "Albums",
+    "Albums": "Album-album",
     "AppDeviceValues": "App: {0}, Device: {1}",
     "AppDeviceValues": "App: {0}, Device: {1}",
     "Application": "Application",
     "Application": "Application",
-    "Artists": "Artists",
+    "Artists": "Artis-artis",
     "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
     "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
-    "Books": "Books",
+    "Books": "Buku-buku",
     "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
     "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
     "Channels": "Channels",
     "Channels": "Channels",
     "ChapterNameValue": "Chapter {0}",
     "ChapterNameValue": "Chapter {0}",

+ 18 - 18
Emby.Server.Implementations/Localization/Core/nl.json

@@ -5,28 +5,28 @@
     "Artists": "Artiesten",
     "Artists": "Artiesten",
     "AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
     "AuthenticationSucceededWithUserName": "{0} is succesvol geverifieerd",
     "Books": "Boeken",
     "Books": "Boeken",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "Er is een nieuwe foto toegevoegd via {0}",
     "Channels": "Kanalen",
     "Channels": "Kanalen",
     "ChapterNameValue": "Hoofdstuk {0}",
     "ChapterNameValue": "Hoofdstuk {0}",
     "Collections": "Collecties",
     "Collections": "Collecties",
-    "DeviceOfflineWithName": "{0} is losgekoppeld",
+    "DeviceOfflineWithName": "{0} heeft de verbinding verbroken",
     "DeviceOnlineWithName": "{0} is verbonden",
     "DeviceOnlineWithName": "{0} is verbonden",
     "FailedLoginAttemptWithUserName": "Mislukte aanmeld poging van {0}",
     "FailedLoginAttemptWithUserName": "Mislukte aanmeld poging van {0}",
     "Favorites": "Favorieten",
     "Favorites": "Favorieten",
     "Folders": "Mappen",
     "Folders": "Mappen",
     "Genres": "Genres",
     "Genres": "Genres",
-    "HeaderAlbumArtists": "Album artiesten",
-    "HeaderCameraUploads": "Camera uploads",
+    "HeaderAlbumArtists": "Albumartiesten",
+    "HeaderCameraUploads": "Camera-uploads",
     "HeaderContinueWatching": "Kijken hervatten",
     "HeaderContinueWatching": "Kijken hervatten",
     "HeaderFavoriteAlbums": "Favoriete albums",
     "HeaderFavoriteAlbums": "Favoriete albums",
     "HeaderFavoriteArtists": "Favoriete artiesten",
     "HeaderFavoriteArtists": "Favoriete artiesten",
     "HeaderFavoriteEpisodes": "Favoriete afleveringen",
     "HeaderFavoriteEpisodes": "Favoriete afleveringen",
     "HeaderFavoriteShows": "Favoriete shows",
     "HeaderFavoriteShows": "Favoriete shows",
-    "HeaderFavoriteSongs": "Favoriete titels",
+    "HeaderFavoriteSongs": "Favoriete nummers",
     "HeaderLiveTV": "Live TV",
     "HeaderLiveTV": "Live TV",
     "HeaderNextUp": "Volgende",
     "HeaderNextUp": "Volgende",
     "HeaderRecordingGroups": "Opnamegroepen",
     "HeaderRecordingGroups": "Opnamegroepen",
-    "HomeVideos": "Thuis video's",
+    "HomeVideos": "Start video's",
     "Inherit": "Overerven",
     "Inherit": "Overerven",
     "ItemAddedWithName": "{0} is toegevoegd aan de bibliotheek",
     "ItemAddedWithName": "{0} is toegevoegd aan de bibliotheek",
     "ItemRemovedWithName": "{0} is verwijderd uit de bibliotheek",
     "ItemRemovedWithName": "{0} is verwijderd uit de bibliotheek",
@@ -34,22 +34,22 @@
     "LabelRunningTimeValue": "Looptijd: {0}",
     "LabelRunningTimeValue": "Looptijd: {0}",
     "Latest": "Nieuwste",
     "Latest": "Nieuwste",
     "MessageApplicationUpdated": "Jellyfin Server is bijgewerkt",
     "MessageApplicationUpdated": "Jellyfin Server is bijgewerkt",
-    "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
+    "MessageApplicationUpdatedTo": "Jellyfin Server is bijgewerkt naar {0}",
     "MessageNamedServerConfigurationUpdatedWithValue": "Sectie {0} van de server configuratie is bijgewerkt",
     "MessageNamedServerConfigurationUpdatedWithValue": "Sectie {0} van de server configuratie is bijgewerkt",
     "MessageServerConfigurationUpdated": "Server configuratie is bijgewerkt",
     "MessageServerConfigurationUpdated": "Server configuratie is bijgewerkt",
     "MixedContent": "Gemengde inhoud",
     "MixedContent": "Gemengde inhoud",
     "Movies": "Films",
     "Movies": "Films",
     "Music": "Muziek",
     "Music": "Muziek",
     "MusicVideos": "Muziekvideo's",
     "MusicVideos": "Muziekvideo's",
-    "NameInstallFailed": "{0} installation failed",
+    "NameInstallFailed": "{0} installatie mislukt",
     "NameSeasonNumber": "Seizoen {0}",
     "NameSeasonNumber": "Seizoen {0}",
     "NameSeasonUnknown": "Seizoen onbekend",
     "NameSeasonUnknown": "Seizoen onbekend",
-    "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
+    "NewVersionIsAvailable": "Een nieuwe versie van Jellyfin Server is beschikbaar om te downloaden.",
     "NotificationOptionApplicationUpdateAvailable": "Programma-update beschikbaar",
     "NotificationOptionApplicationUpdateAvailable": "Programma-update beschikbaar",
     "NotificationOptionApplicationUpdateInstalled": "Programma-update geïnstalleerd",
     "NotificationOptionApplicationUpdateInstalled": "Programma-update geïnstalleerd",
-    "NotificationOptionAudioPlayback": "Geluid gestart",
-    "NotificationOptionAudioPlaybackStopped": "Geluid gestopt",
-    "NotificationOptionCameraImageUploaded": "Camera afbeelding geüpload",
+    "NotificationOptionAudioPlayback": "Muziek gestart",
+    "NotificationOptionAudioPlaybackStopped": "Muziek gestopt",
+    "NotificationOptionCameraImageUploaded": "Camera-afbeelding geüpload",
     "NotificationOptionInstallationFailed": "Installatie mislukt",
     "NotificationOptionInstallationFailed": "Installatie mislukt",
     "NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
     "NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd",
     "NotificationOptionPluginError": "Plug-in fout",
     "NotificationOptionPluginError": "Plug-in fout",
@@ -70,12 +70,12 @@
     "ProviderValue": "Aanbieder: {0}",
     "ProviderValue": "Aanbieder: {0}",
     "ScheduledTaskFailedWithName": "{0} is mislukt",
     "ScheduledTaskFailedWithName": "{0} is mislukt",
     "ScheduledTaskStartedWithName": "{0} is gestart",
     "ScheduledTaskStartedWithName": "{0} is gestart",
-    "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
+    "ServerNameNeedsToBeRestarted": "{0} moet herstart worden",
     "Shows": "Series",
     "Shows": "Series",
-    "Songs": "Titels",
+    "Songs": "Nummers",
     "StartupEmbyServerIsLoading": "Jellyfin Server is aan het laden, probeer het later opnieuw.",
     "StartupEmbyServerIsLoading": "Jellyfin Server is aan het laden, probeer het later opnieuw.",
     "SubtitleDownloadFailureForItem": "Downloaden van ondertiteling voor {0} is mislukt",
     "SubtitleDownloadFailureForItem": "Downloaden van ondertiteling voor {0} is mislukt",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Ondertitels konden niet gedownload worden van {0} voor {1}",
     "SubtitlesDownloadedForItem": "Ondertiteling voor {0} is gedownload",
     "SubtitlesDownloadedForItem": "Ondertiteling voor {0} is gedownload",
     "Sync": "Synchronisatie",
     "Sync": "Synchronisatie",
     "System": "Systeem",
     "System": "Systeem",
@@ -89,9 +89,9 @@
     "UserOnlineFromDevice": "{0} heeft verbinding met {1}",
     "UserOnlineFromDevice": "{0} heeft verbinding met {1}",
     "UserPasswordChangedWithName": "Wachtwoord voor {0} is gewijzigd",
     "UserPasswordChangedWithName": "Wachtwoord voor {0} is gewijzigd",
     "UserPolicyUpdatedWithName": "Gebruikersbeleid gewijzigd voor {0}",
     "UserPolicyUpdatedWithName": "Gebruikersbeleid gewijzigd voor {0}",
-    "UserStartedPlayingItemWithValues": "{0} heeft afspelen van {1} gestart",
-    "UserStoppedPlayingItemWithValues": "{0} heeft afspelen van {1} gestopt",
-    "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+    "UserStartedPlayingItemWithValues": "{0} heeft afspelen van {1} gestart op {2}",
+    "UserStoppedPlayingItemWithValues": "{0} heeft afspelen van {1} gestopt op {2}",
+    "ValueHasBeenAddedToLibrary": "{0} is toegevoegd aan je mediabibliotheek",
     "ValueSpecialEpisodeName": "Speciaal - {0}",
     "ValueSpecialEpisodeName": "Speciaal - {0}",
     "VersionNumber": "Versie {0}"
     "VersionNumber": "Versie {0}"
 }
 }

+ 5 - 5
Emby.Server.Implementations/Localization/Core/ru.json

@@ -5,7 +5,7 @@
     "Artists": "Исполнители",
     "Artists": "Исполнители",
     "AuthenticationSucceededWithUserName": "{0} - авторизация успешна",
     "AuthenticationSucceededWithUserName": "{0} - авторизация успешна",
     "Books": "Литература",
     "Books": "Литература",
-    "CameraImageUploadedFrom": "Новое фото было выложено с {0}",
+    "CameraImageUploadedFrom": "Новое фото было выложено с камеры {0}",
     "Channels": "Каналы",
     "Channels": "Каналы",
     "ChapterNameValue": "Сцена {0}",
     "ChapterNameValue": "Сцена {0}",
     "Collections": "Коллекции",
     "Collections": "Коллекции",
@@ -31,20 +31,20 @@
     "ItemAddedWithName": "{0} - добавлено в медиатеку",
     "ItemAddedWithName": "{0} - добавлено в медиатеку",
     "ItemRemovedWithName": "{0} - изъято из медиатеки",
     "ItemRemovedWithName": "{0} - изъято из медиатеки",
     "LabelIpAddressValue": "IP-адрес: {0}",
     "LabelIpAddressValue": "IP-адрес: {0}",
-    "LabelRunningTimeValue": "Время выполнения: {0}",
+    "LabelRunningTimeValue": "Длительность: {0}",
     "Latest": "Новейшее",
     "Latest": "Новейшее",
     "MessageApplicationUpdated": "Jellyfin Server был обновлён",
     "MessageApplicationUpdated": "Jellyfin Server был обновлён",
     "MessageApplicationUpdatedTo": "Jellyfin Server был обновлён до {0}",
     "MessageApplicationUpdatedTo": "Jellyfin Server был обновлён до {0}",
     "MessageNamedServerConfigurationUpdatedWithValue": "Конфиг-ия сервера (раздел {0}) была обновлена",
     "MessageNamedServerConfigurationUpdatedWithValue": "Конфиг-ия сервера (раздел {0}) была обновлена",
     "MessageServerConfigurationUpdated": "Конфиг-ия сервера была обновлена",
     "MessageServerConfigurationUpdated": "Конфиг-ия сервера была обновлена",
-    "MixedContent": "Смешанное содержание",
+    "MixedContent": "Смешанное содержимое",
     "Movies": "Кино",
     "Movies": "Кино",
     "Music": "Музыка",
     "Music": "Музыка",
     "MusicVideos": "Муз. видео",
     "MusicVideos": "Муз. видео",
     "NameInstallFailed": "Установка {0} неудачна",
     "NameInstallFailed": "Установка {0} неудачна",
     "NameSeasonNumber": "Сезон {0}",
     "NameSeasonNumber": "Сезон {0}",
     "NameSeasonUnknown": "Сезон неопознан",
     "NameSeasonUnknown": "Сезон неопознан",
-    "NewVersionIsAvailable": "Имеется новая версия Jellyfin Server",
+    "NewVersionIsAvailable": "Новая версия Jellyfin Server доступна для загрузки.",
     "NotificationOptionApplicationUpdateAvailable": "Имеется обновление приложения",
     "NotificationOptionApplicationUpdateAvailable": "Имеется обновление приложения",
     "NotificationOptionApplicationUpdateInstalled": "Обновление приложения установлено",
     "NotificationOptionApplicationUpdateInstalled": "Обновление приложения установлено",
     "NotificationOptionAudioPlayback": "Воспр-ие аудио зап-но",
     "NotificationOptionAudioPlayback": "Воспр-ие аудио зап-но",
@@ -75,7 +75,7 @@
     "Songs": "Композиции",
     "Songs": "Композиции",
     "StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
     "StartupEmbyServerIsLoading": "Jellyfin Server загружается. Повторите попытку в ближайшее время.",
     "SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",
     "SubtitleDownloadFailureForItem": "Субтитры к {0} не удалось загрузить",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Субтитры к {1} не удалось загрузить с {0}",
     "SubtitlesDownloadedForItem": "Субтитры к {0} загружены",
     "SubtitlesDownloadedForItem": "Субтитры к {0} загружены",
     "Sync": "Синхро",
     "Sync": "Синхро",
     "System": "Система",
     "System": "Система",

+ 15 - 25
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -116,6 +116,7 @@ namespace Emby.Server.Implementations.Updates
         private readonly IApplicationHost _applicationHost;
         private readonly IApplicationHost _applicationHost;
 
 
         private readonly ICryptoProvider _cryptographyProvider;
         private readonly ICryptoProvider _cryptographyProvider;
+        private readonly IZipClient _zipClient;
 
 
         // netframework or netcore
         // netframework or netcore
         private readonly string _packageRuntime;
         private readonly string _packageRuntime;
@@ -129,6 +130,7 @@ namespace Emby.Server.Implementations.Updates
             IServerConfigurationManager config,
             IServerConfigurationManager config,
             IFileSystem fileSystem,
             IFileSystem fileSystem,
             ICryptoProvider cryptographyProvider,
             ICryptoProvider cryptographyProvider,
+            IZipClient zipClient,
             string packageRuntime)
             string packageRuntime)
         {
         {
             if (loggerFactory == null)
             if (loggerFactory == null)
@@ -146,6 +148,7 @@ namespace Emby.Server.Implementations.Updates
             _config = config;
             _config = config;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _cryptographyProvider = cryptographyProvider;
             _cryptographyProvider = cryptographyProvider;
+            _zipClient = zipClient;
             _packageRuntime = packageRuntime;
             _packageRuntime = packageRuntime;
             _logger = loggerFactory.CreateLogger(nameof(InstallationManager));
             _logger = loggerFactory.CreateLogger(nameof(InstallationManager));
         }
         }
@@ -526,14 +529,18 @@ namespace Emby.Server.Implementations.Updates
 
 
         private async Task PerformPackageInstallation(IProgress<double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken)
         private async Task PerformPackageInstallation(IProgress<double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken)
         {
         {
-            // Target based on if it is an archive or single assembly
-            //  zip archives are assumed to contain directory structures relative to our ProgramDataPath
             var extension = Path.GetExtension(package.targetFilename);
             var extension = Path.GetExtension(package.targetFilename);
-            var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase);
+            var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase);
+
+            if (!isArchive)
+            {
+                _logger.LogError("Only zip packages are supported. {Filename} is not a zip archive.", package.targetFilename);
+                return;
+            }
 
 
             if (target == null)
             if (target == null)
             {
             {
-                target = Path.Combine(isArchive ? _appPaths.TempUpdatePath : _appPaths.PluginsPath, package.targetFilename);
+                target = Path.Combine(_appPaths.PluginsPath, Path.GetFileNameWithoutExtension(package.targetFilename));
             }
             }
 
 
             // Download to temporary file so that, if interrupted, it won't destroy the existing installation
             // Download to temporary file so that, if interrupted, it won't destroy the existing installation
@@ -547,36 +554,19 @@ namespace Emby.Server.Implementations.Updates
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
-            // Validate with a checksum
-            var packageChecksum = string.IsNullOrWhiteSpace(package.checksum) ? Guid.Empty : new Guid(package.checksum);
-            if (!packageChecksum.Equals(Guid.Empty)) // support for legacy uploads for now
-            {
-                using (var stream = File.OpenRead(tempFile))
-                {
-                    var check = Guid.Parse(BitConverter.ToString(_cryptographyProvider.ComputeMD5(stream)).Replace("-", string.Empty));
-                    if (check != packageChecksum)
-                    {
-                        throw new Exception(string.Format("Download validation failed for {0}.  Probably corrupted during transfer.", package.name));
-                    }
-                }
-            }
-
-            cancellationToken.ThrowIfCancellationRequested();
+            // TODO: Validate with a checksum, *properly*
 
 
             // Success - move it to the real target
             // Success - move it to the real target
             try
             try
             {
             {
-                Directory.CreateDirectory(Path.GetDirectoryName(target));
-                File.Copy(tempFile, target, true);
-                //If it is an archive - write out a version file so we know what it is
-                if (isArchive)
+                using (var stream = File.OpenRead(tempFile))
                 {
                 {
-                    File.WriteAllText(target + ".ver", package.versionStr);
+                    _zipClient.ExtractAllFromZip(stream, target, true);
                 }
                 }
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {
-                _logger.LogError(ex, "Error attempting to move file from {TempFile} to {TargetFile}", tempFile, target);
+                _logger.LogError(ex, "Error attempting to extract {TempFile} to {TargetFile}", tempFile, target);
                 throw;
                 throw;
             }
             }
 
 

+ 0 - 2
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -8,7 +8,6 @@ using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Devices;
@@ -71,7 +70,6 @@ namespace MediaBrowser.Api.Playback
         protected IMediaSourceManager MediaSourceManager { get; private set; }
         protected IMediaSourceManager MediaSourceManager { get; private set; }
         protected IJsonSerializer JsonSerializer { get; private set; }
         protected IJsonSerializer JsonSerializer { get; private set; }
 
 
-        public static IHttpClient HttpClient;
         protected IAuthorizationContext AuthorizationContext { get; private set; }
         protected IAuthorizationContext AuthorizationContext { get; private set; }
 
 
         protected EncodingHelper EncodingHelper { get; set; }
         protected EncodingHelper EncodingHelper { get; set; }

+ 4 - 1
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -1,4 +1,5 @@
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
@@ -33,6 +34,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     public class AudioService : BaseProgressiveStreamingService
     public class AudioService : BaseProgressiveStreamingService
     {
     {
         public AudioService(
         public AudioService(
+            IHttpClient httpClient,
             IServerConfigurationManager serverConfig,
             IServerConfigurationManager serverConfig,
             IUserManager userManager,
             IUserManager userManager,
             ILibraryManager libraryManager,
             ILibraryManager libraryManager,
@@ -46,7 +48,8 @@ namespace MediaBrowser.Api.Playback.Progressive
             IJsonSerializer jsonSerializer,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext,
             IAuthorizationContext authorizationContext,
             IEnvironmentInfo environmentInfo)
             IEnvironmentInfo environmentInfo)
-                : base(serverConfig,
+                : base(httpClient,
+                    serverConfig,
                     userManager,
                     userManager,
                     libraryManager,
                     libraryManager,
                     isoManager,
                     isoManager,

+ 3 - 0
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -26,8 +26,10 @@ namespace MediaBrowser.Api.Playback.Progressive
     public abstract class BaseProgressiveStreamingService : BaseStreamingService
     public abstract class BaseProgressiveStreamingService : BaseStreamingService
     {
     {
         protected readonly IEnvironmentInfo EnvironmentInfo;
         protected readonly IEnvironmentInfo EnvironmentInfo;
+        protected IHttpClient HttpClient { get; private set; }
 
 
         public BaseProgressiveStreamingService(
         public BaseProgressiveStreamingService(
+            IHttpClient httpClient,
             IServerConfigurationManager serverConfig,
             IServerConfigurationManager serverConfig,
             IUserManager userManager,
             IUserManager userManager,
             ILibraryManager libraryManager,
             ILibraryManager libraryManager,
@@ -55,6 +57,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 authorizationContext)
                 authorizationContext)
         {
         {
             EnvironmentInfo = environmentInfo;
             EnvironmentInfo = environmentInfo;
+            HttpClient = httpClient;
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 4 - 1
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -1,4 +1,5 @@
 using System.Threading.Tasks;
 using System.Threading.Tasks;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Devices;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
@@ -69,6 +70,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     public class VideoService : BaseProgressiveStreamingService
     public class VideoService : BaseProgressiveStreamingService
     {
     {
         public VideoService(
         public VideoService(
+            IHttpClient httpClient,
             IServerConfigurationManager serverConfig,
             IServerConfigurationManager serverConfig,
             IUserManager userManager,
             IUserManager userManager,
             ILibraryManager libraryManager,
             ILibraryManager libraryManager,
@@ -82,7 +84,8 @@ namespace MediaBrowser.Api.Playback.Progressive
             IJsonSerializer jsonSerializer,
             IJsonSerializer jsonSerializer,
             IAuthorizationContext authorizationContext,
             IAuthorizationContext authorizationContext,
             IEnvironmentInfo environmentInfo)
             IEnvironmentInfo environmentInfo)
-            : base(serverConfig,
+            : base(httpClient,
+                serverConfig,
                 userManager,
                 userManager,
                 libraryManager,
                 libraryManager,
                 isoManager,
                 isoManager,

+ 5 - 1
MediaBrowser.Api/Playback/UniversalAudioService.cs

@@ -77,6 +77,7 @@ namespace MediaBrowser.Api.Playback
     public class UniversalAudioService : BaseApiService
     public class UniversalAudioService : BaseApiService
     {
     {
         public UniversalAudioService(
         public UniversalAudioService(
+            IHttpClient httpClient,
             IServerConfigurationManager serverConfigurationManager,
             IServerConfigurationManager serverConfigurationManager,
             IUserManager userManager,
             IUserManager userManager,
             ILibraryManager libraryManager,
             ILibraryManager libraryManager,
@@ -95,6 +96,7 @@ namespace MediaBrowser.Api.Playback
             IEnvironmentInfo environmentInfo,
             IEnvironmentInfo environmentInfo,
             ILoggerFactory loggerFactory)
             ILoggerFactory loggerFactory)
         {
         {
+            HttpClient = httpClient;
             ServerConfigurationManager = serverConfigurationManager;
             ServerConfigurationManager = serverConfigurationManager;
             UserManager = userManager;
             UserManager = userManager;
             LibraryManager = libraryManager;
             LibraryManager = libraryManager;
@@ -115,6 +117,7 @@ namespace MediaBrowser.Api.Playback
             _logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
             _logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
         }
         }
 
 
+        protected IHttpClient HttpClient { get; private set; }
         protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
         protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
         protected IUserManager UserManager { get; private set; }
         protected IUserManager UserManager { get; private set; }
         protected ILibraryManager LibraryManager { get; private set; }
         protected ILibraryManager LibraryManager { get; private set; }
@@ -323,7 +326,8 @@ namespace MediaBrowser.Api.Playback
             }
             }
             else
             else
             {
             {
-                var service = new AudioService(ServerConfigurationManager,
+                var service = new AudioService(HttpClient,
+                    ServerConfigurationManager,
                     UserManager,
                     UserManager,
                     LibraryManager,
                     LibraryManager,
                     IsoManager,
                     IsoManager,

+ 0 - 2
MediaBrowser.Controller/Net/StaticResultOptions.cs

@@ -12,8 +12,6 @@ namespace MediaBrowser.Controller.Net
         public string ContentType { get; set; }
         public string ContentType { get; set; }
         public TimeSpan? CacheDuration { get; set; }
         public TimeSpan? CacheDuration { get; set; }
         public DateTime? DateLastModified { get; set; }
         public DateTime? DateLastModified { get; set; }
-        public Guid CacheKey { get; set; }
-
         public Func<Task<Stream>> ContentFactory { get; set; }
         public Func<Task<Stream>> ContentFactory { get; set; }
 
 
         public bool IsHeadRequest { get; set; }
         public bool IsHeadRequest { get; set; }

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

@@ -297,7 +297,7 @@ namespace MediaBrowser.Model.Dlna
             int? inputAudioChannels = audioStream?.Channels;
             int? inputAudioChannels = audioStream?.Channels;
             int? inputAudioBitrate = audioStream?.BitDepth;
             int? inputAudioBitrate = audioStream?.BitDepth;
             int? inputAudioSampleRate = audioStream?.SampleRate;
             int? inputAudioSampleRate = audioStream?.SampleRate;
-            int? inputAudioBitDepth = audioStream.BitDepth;
+            int? inputAudioBitDepth = audioStream?.BitDepth;
 
 
             if (directPlayMethods.Count() > 0)
             if (directPlayMethods.Count() > 0)
             {
             {

+ 1 - 1
MediaBrowser.WebDashboard/jellyfin-web

@@ -1 +1 @@
-Subproject commit c7ce1ac8eccd50f1bd759b30fbe60ea797ffe86e
+Subproject commit b4842e325e9d7d708193b4a27060cfe4c978df5e

+ 2 - 2
SharedVersion.cs

@@ -1,4 +1,4 @@
 using System.Reflection;
 using System.Reflection;
 
 
-[assembly: AssemblyVersion("10.1.0")]
-[assembly: AssemblyFileVersion("10.1.0")]
+[assembly: AssemblyVersion("10.2.0")]
+[assembly: AssemblyFileVersion("10.2.0")]

+ 108 - 0
deployment/debian-package-x64/pkg-src/changelog

@@ -1,3 +1,111 @@
+jellyfin (10.2.0-2) unstable; urgency=medium
+
+  * jellyfin:
+  * PR452 Use EF Core for Activity database
+  * PR535 Clean up streambuilder
+  * PR655 Support trying local branches in submodule
+  * PR656 Do some logging in MediaInfoService
+  * PR657 Remove conditions that are always true/false
+  * PR661 Fix NullRef from progress report
+  * PR663 Use TagLibSharp Nuget package
+  * PR664 Revert "Fix segment_time_delta for ffmpeg 4.1"
+  * PR666 Add cross-platform build for arm64
+  * PR668 Return Audio objects from MusicAlbum.Tracks
+  * PR671 Set EnableRaisingEvents correctly
+  * PR672 Remove unconditional caching, modified since header and use ETags
+  * PR677 Fix arm32 Docker
+  * PR681 Fix Windows build script errors + pin ffmpeg to 4.0
+  * PR686 Disable some StyleCop warnings
+  * PR687 Fix some analyzer warnings
+  * PR689 Fix RPM package build for fedora
+  * PR702 Fix debug build on windows
+  * PR706 Make another docker layer reusable
+  * PR709 Fix always null expressions
+  * PR710 Fix a spelling mistake
+  * PR711 Remove remnants of system events
+  * PR713 Fix empty statement in DidlBuilder.cs
+  * PR716 Remove more compile time warnings
+  * PR721 Change image dimentions from double to int
+  * PR723 Minor improvements to db code
+  * PR724 Move Skia back into it's own project
+  * PR726 Clean up IFileSystem wrappers around stdlib.
+  * PR727 Change default aspect ratio to 2/3 from 0
+  * PR728 Use ffmpeg from jrottenberg/ffmpeg
+  * PR732 Reworked LocalizationManager to load data async
+  * PR733 Remove unused function
+  * PR734 Fix more analyzer warnings
+  * PR736 Start startup tasks async
+  * PR737 Add AssemblyInfo for Jellyfin.Drawing.Skia
+  * PR739 Change multi version logic for movies
+  * PR740 Remove code for pre-installed plugins & properly check if file exists
+  * PR756 Make cache dir configurable
+  * PR757 Fix default aspect ratio
+  * PR758 Add password field to initial setup
+  * PR764 Remove dead code, made some functions properly async
+  * PR769 Fix conditions where the ! was swallowed in #726
+  * PR774 reimplement support for plugin repository
+  * PR782 Remove commented file MediaBrowser.LocalMetadata.Savers.PersonXmlSaver
+  * PR783 Update builds to use #749 and #756
+  * PR788 Fix more warnings
+  * PR794 Remove MoreLINQ
+  * PR797 Fix all warnings
+  * PR798 Cleanup around the api endpoints
+  * PR800 Add CentOS and update rpm spec for the cachedir option
+  * PR802 Fix build error
+  * PR804 Handle new option parser properly
+  * PR805 Add weblate translation status to README
+  * PR807 Fix restart script in OS packages
+  * PR810 Fix loading of rating files
+  * PR812 Fix up the explicit docs links in the README
+  * PR819 Some small changes in Device.cs and DidlBuilder.cs
+  * PR822 Complete rename ImageSize -> ImageDimensions
+  * PR824 Improved Docker pkgbuild
+  * PR831 Move some arrays to generics
+  * PR833 Add await to GetCountries in LocalizationService
+  * PR834 Add donation badge and reorganize badges
+  * PR838 Quick style fix
+  * PR840 Fix more warnings
+  * PR841 Fix OC badge to all and add forum badge
+  * PR842 Use VAAPI-enabled ffmpeg
+  * PR852 Use SQLitePCL.pretty.netstandard on NuGet
+  * PR853 Fix poor handling of cache directories
+  * PR864: Add support for ZIP plugin archives
+  * PR868: Fix audio streaming via BaseProgressiveStreamingService
+  * PR869: Remove DLL support and require all packages/plugins to be zip archives
+  * PR872: Fix potential NullReferenceException
+  * PR890: Drop ETag and use Last-Modified header
+  * PR892: Add jellyfin-ffmpeg and versioning to package deps
+  * PR899: DLNA: Fix race condition leading to missing device names
+  * PR901: Properly dispose HttpWebResponse when the request failed to avoid 'too many open files'
+  * PR909: Fix docker arm builds
+  * PR910: Enhance Dockerfiles
+  * PR911: Checkout submodules in Docker Hub hook
+  * jellyfin-web:
+  * PR51 remove more code for sync and camera roll
+  * PR56 Use English for fallback translations and clean up language files
+  * PR58 Css slider fixes
+  * PR62 remove BOM markers
+  * PR65 Fix profile image not being shown on profile page
+  * PR73 Dev sync
+  * PR74 Add download menu option to media items
+  * PR75 User profile fixes
+  * PR76 Fix syntax error caused by deminification
+  * PR79 Remove unused Connect related from the frontend
+  * PR80 Remove games
+  * PR92 Added frontend support for a password field on setup
+  * PR94 Update british strings
+  * PR95 add display language option back
+  * PR112 Removed seasonal theme support
+  * PR116 Consolidate all strings into a single file per language
+  * PR117 Fix volume slider behavior
+  * PR118 Enable and fix PiP for Safari
+  * PR119 Make the toggle track visible on all themes
+  * PR121 Fix syntax error in site.js
+  * PR127 Change sharedcomponents module to core
+  * PR135 Make sure fallback culture is always available
+
+ -- Jellyfin Packaging Team <packaging@jellyfin.org>  Fri, 15 Feb 2019 20:51:25 -0500
+
 jellyfin (10.1.0-1) unstable; urgency=medium
 jellyfin (10.1.0-1) unstable; urgency=medium
 
 
   * jellyfin:
   * jellyfin:

+ 6 - 1
deployment/debian-package-x64/pkg-src/control

@@ -18,6 +18,11 @@ Replaces: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
 Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
 Breaks: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
 Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
 Conflicts: mediabrowser, emby, emby-server-beta, jellyfin-dev, emby-server
 Architecture: any
 Architecture: any
-Depends: at, libsqlite3-0, ffmpeg, libfontconfig1, libfreetype6, libssl1.0.0 | libssl1.0.2
+Depends: at,
+         libsqlite3-0,
+         ffmpeg (<7:4.1) | jellyfin-ffmpeg,
+         libfontconfig1,
+         libfreetype6,
+         libssl1.0.0 | libssl1.0.2
 Description: Jellyfin is a home media server.
 Description: Jellyfin is a home media server.
  It is built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono. It features a REST-based api with built-in documentation to facilitate client development. We also have client libraries for our api to enable rapid development.
  It is built on top of other popular open source technologies such as Service Stack, jQuery, jQuery mobile, and Mono. It features a REST-based api with built-in documentation to facilitate client development. We also have client libraries for our api to enable rapid development.

+ 106 - 2
deployment/fedora-package-x64/pkg-src/jellyfin.spec

@@ -7,8 +7,8 @@
 %endif
 %endif
 
 
 Name:           jellyfin
 Name:           jellyfin
-Version:        10.1.0
-Release:        1%{?dist}
+Version:        10.2.0
+Release:        2%{?dist}
 Summary:        The Free Software Media Browser
 Summary:        The Free Software Media Browser
 License:        GPLv2
 License:        GPLv2
 URL:            https://jellyfin.media
 URL:            https://jellyfin.media
@@ -140,6 +140,110 @@ fi
 %systemd_postun_with_restart jellyfin.service
 %systemd_postun_with_restart jellyfin.service
 
 
 %changelog
 %changelog
+* Fri Feb 15 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
+- jellyfin:
+- PR452 Use EF Core for Activity database
+- PR535 Clean up streambuilder
+- PR655 Support trying local branches in submodule
+- PR656 Do some logging in MediaInfoService
+- PR657 Remove conditions that are always true/false
+- PR661 Fix NullRef from progress report
+- PR663 Use TagLibSharp Nuget package
+- PR664 Revert "Fix segment_time_delta for ffmpeg 4.1"
+- PR666 Add cross-platform build for arm64
+- PR668 Return Audio objects from MusicAlbum.Tracks
+- PR671 Set EnableRaisingEvents correctly
+- PR672 Remove unconditional caching, modified since header and use ETags
+- PR677 Fix arm32 Docker
+- PR681 Fix Windows build script errors + pin ffmpeg to 4.0
+- PR686 Disable some StyleCop warnings
+- PR687 Fix some analyzer warnings
+- PR689 Fix RPM package build for fedora
+- PR702 Fix debug build on windows
+- PR706 Make another docker layer reusable
+- PR709 Fix always null expressions
+- PR710 Fix a spelling mistake
+- PR711 Remove remnants of system events
+- PR713 Fix empty statement in DidlBuilder.cs
+- PR716 Remove more compile time warnings
+- PR721 Change image dimentions from double to int
+- PR723 Minor improvements to db code
+- PR724 Move Skia back into it's own project
+- PR726 Clean up IFileSystem wrappers around stdlib.
+- PR727 Change default aspect ratio to 2/3 from 0
+- PR728 Use ffmpeg from jrottenberg/ffmpeg
+- PR732 Reworked LocalizationManager to load data async
+- PR733 Remove unused function
+- PR734 Fix more analyzer warnings
+- PR736 Start startup tasks async
+- PR737 Add AssemblyInfo for Jellyfin.Drawing.Skia
+- PR739 Change multi version logic for movies
+- PR740 Remove code for pre-installed plugins & properly check if file exists
+- PR756 Make cache dir configurable
+- PR757 Fix default aspect ratio
+- PR758 Add password field to initial setup
+- PR764 Remove dead code, made some functions properly async
+- PR769 Fix conditions where the ! was swallowed in #726
+- PR774 reimplement support for plugin repository
+- PR782 Remove commented file MediaBrowser.LocalMetadata.Savers.PersonXmlSaver
+- PR783 Update builds to use #749 and #756
+- PR788 Fix more warnings
+- PR794 Remove MoreLINQ
+- PR797 Fix all warnings
+- PR798 Cleanup around the api endpoints
+- PR800 Add CentOS and update rpm spec for the cachedir option
+- PR802 Fix build error
+- PR804 Handle new option parser properly
+- PR805 Add weblate translation status to README
+- PR807 Fix restart script in OS packages
+- PR810 Fix loading of rating files
+- PR812 Fix up the explicit docs links in the README
+- PR819 Some small changes in Device.cs and DidlBuilder.cs
+- PR822 Complete rename ImageSize -> ImageDimensions
+- PR824 Improved Docker pkgbuild
+- PR831 Move some arrays to generics
+- PR833 Add await to GetCountries in LocalizationService
+- PR834 Add donation badge and reorganize badges
+- PR838 Quick style fix
+- PR840 Fix more warnings
+- PR841 Fix OC badge to all and add forum badge
+- PR842 Use VAAPI-enabled ffmpeg
+- PR852 Use SQLitePCL.pretty.netstandard on NuGet
+- PR853 Fix poor handling of cache directories
+- PR864 Add support for ZIP plugin archives
+- PR868 Fix audio streaming via BaseProgressiveStreamingService
+- PR869 Remove DLL support and require all packages/plugins to be zip archives
+- PR872 Fix potential NullReferenceException
+- PR899: DLNA: Fix race condition leading to missing device names
+- PR890 Drop ETag and use Last-Modified header
+- PR892: Add jellyfin-ffmpeg and versioning to package deps
+- PR901: Properly dispose HttpWebResponse when the request failed to avoid 'too many open files'
+- PR909: Fix docker arm builds
+- PR910: Enhance Dockerfiles
+- PR911: Checkout submodules in Docker Hub hook
+- jellyfin-web:
+- PR51 remove more code for sync and camera roll
+- PR56 Use English for fallback translations and clean up language files
+- PR58 Css slider fixes
+- PR62 remove BOM markers
+- PR65 Fix profile image not being shown on profile page
+- PR73 Dev sync
+- PR74 Add download menu option to media items
+- PR75 User profile fixes
+- PR76 Fix syntax error caused by deminification
+- PR79 Remove unused Connect related from the frontend
+- PR80 Remove games
+- PR92 Added frontend support for a password field on setup
+- PR94 Update british strings
+- PR95 add display language option back
+- PR112 Removed seasonal theme support
+- PR116 Consolidate all strings into a single file per language
+- PR117 Fix volume slider behavior
+- PR118 Enable and fix PiP for Safari
+- PR119 Make the toggle track visible on all themes
+- PR121 Fix syntax error in site.js
+- PR127 Change sharedcomponents module to core
+- PR135 Make sure fallback culture is always available
 * Sun Jan 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
 * Sun Jan 20 2019 Jellyfin Packaging Team <packaging@jellyfin.org>
 - jellyfin:
 - jellyfin:
 - PR335 Build scripts and build system consolidation.
 - PR335 Build scripts and build system consolidation.

+ 2 - 1
deployment/win-x64/package.sh

@@ -1,4 +1,5 @@
 #!/usr/bin/env bash
 #!/usr/bin/env bash
+set -x
 package_win64() (
 package_win64() (
     local NSSM_VERSION="nssm-2.24-101-g897c7ad"
     local NSSM_VERSION="nssm-2.24-101-g897c7ad"
     local NSSM_URL="https://nssm.cc/ci/${NSSM_VERSION}.zip"
     local NSSM_URL="https://nssm.cc/ci/${NSSM_VERSION}.zip"
@@ -15,7 +16,7 @@ package_win64() (
         wget ${NSSM_URL} -O ${TEMP_DIR}/nssm.zip
         wget ${NSSM_URL} -O ${TEMP_DIR}/nssm.zip
         wget ${FFMPEG_URL} -O ${TEMP_DIR}/ffmpeg.zip
         wget ${FFMPEG_URL} -O ${TEMP_DIR}/ffmpeg.zip
         unzip ${TEMP_DIR}/nssm.zip -d $TEMP_DIR
         unzip ${TEMP_DIR}/nssm.zip -d $TEMP_DIR
-        cp ${TEMP_DIR}/${NSSM_VERSION}}/win64/nssm.exe ${OUTPUT_DIR}/nssm.exe
+        cp ${TEMP_DIR}/${NSSM_VERSION}/win64/nssm.exe ${OUTPUT_DIR}/nssm.exe
         unzip ${TEMP_DIR}/ffmpeg.zip -d $TEMP_DIR
         unzip ${TEMP_DIR}/ffmpeg.zip -d $TEMP_DIR
         cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffmpeg.exe ${OUTPUT_DIR}/ffmpeg.exe
         cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffmpeg.exe ${OUTPUT_DIR}/ffmpeg.exe
         cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffprobe.exe ${OUTPUT_DIR}/ffprobe.exe
         cp ${TEMP_DIR}/${FFMPEG_VERSION}/bin/ffprobe.exe ${OUTPUT_DIR}/ffprobe.exe

+ 6 - 0
hooks/pre_build

@@ -0,0 +1,6 @@
+#!/bin/bash
+git submodule update --init --recursive
+
+# Register qemu-*-static for all supported processors except the 
+# current one, but also remove all registered binfmt_misc before
+docker run --rm --privileged multiarch/qemu-user-static:register --reset