diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 1b4fdc8c4..e383d02b7 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -78,6 +78,7 @@
- [nvllsvm](https://github.com/nvllsvm)
- [nyanmisaka](https://github.com/nyanmisaka)
- [oddstr13](https://github.com/oddstr13)
+ - [orryverducci](https://github.com/orryverducci)
- [petermcneil](https://github.com/petermcneil)
- [Phlogi](https://github.com/Phlogi)
- [pjeanjean](https://github.com/pjeanjean)
diff --git a/Dockerfile b/Dockerfile
index d3fb138a8..4fdffc740 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,7 +14,7 @@ COPY . .
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
-RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none"
FROM debian:buster-slim
diff --git a/Dockerfile.arm b/Dockerfile.arm
index 59b8a8c98..751ab8611 100644
--- a/Dockerfile.arm
+++ b/Dockerfile.arm
@@ -21,7 +21,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
-RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none"
FROM multiarch/qemu-user-static:x86_64-arm as qemu
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 1a691b572..0d2e91d91 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -21,7 +21,7 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# Discard objs - may cause failures if exists
RUN find . -type d -name obj | xargs -r rm -r
# Build
-RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none"
FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
FROM arm64v8/debian:buster-slim
diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs
index be1ed7872..4b108b89e 100644
--- a/Emby.Dlna/ContentDirectory/ControlHandler.cs
+++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs
@@ -1363,7 +1363,7 @@ namespace Emby.Dlna.ContentDirectory
};
}
- Logger.LogError("Error parsing item Id: {id}. Returning user root folder.", id);
+ Logger.LogError("Error parsing item Id: {Id}. Returning user root folder.", id);
return new ServerItem(_libraryManager.GetUserRootFolder());
}
diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index bd09a8051..5b8a89d8f 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -948,7 +948,7 @@ namespace Emby.Dlna.Didl
}
catch (XmlException ex)
{
- _logger.LogError(ex, "Error adding xml value: {value}", name);
+ _logger.LogError(ex, "Error adding xml value: {Value}", name);
}
}
@@ -960,7 +960,7 @@ namespace Emby.Dlna.Didl
}
catch (XmlException ex)
{
- _logger.LogError(ex, "Error adding xml value: {value}", value);
+ _logger.LogError(ex, "Error adding xml value: {Value}", value);
}
}
diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index d4a8268b9..4ab0a2a3f 100644
--- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -308,7 +308,7 @@ namespace Emby.Server.Implementations.AppBase
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error loading configuration file: {path}", path);
+ Logger.LogError(ex, "Error loading configuration file: {Path}", path);
return Activator.CreateInstance(configurationType);
}
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 8e9a581ea..155bdcf65 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -279,6 +279,10 @@ namespace Emby.Server.Implementations
Password = ServerConfigurationManager.Configuration.CertificatePassword
};
Certificate = GetCertificate(CertificateInfo);
+
+ ApplicationVersion = typeof(ApplicationHost).Assembly.GetName().Version;
+ ApplicationVersionString = ApplicationVersion.ToString(3);
+ ApplicationUserAgent = Name.Replace(' ', '-') + "/" + ApplicationVersionString;
}
public string ExpandVirtualPath(string path)
@@ -308,16 +312,16 @@ namespace Emby.Server.Implementations
}
///
- public Version ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version;
+ public Version ApplicationVersion { get; }
///
- public string ApplicationVersionString { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
+ public string ApplicationVersionString { get; }
///
/// Gets the current application user agent.
///
/// The application user agent.
- public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersionString;
+ public string ApplicationUserAgent { get; }
///
/// Gets the email address for use within a comment section of a user agent field.
@@ -1401,7 +1405,7 @@ namespace Emby.Server.Implementations
foreach (var assembly in assemblies)
{
- Logger.LogDebug("Found API endpoints in plugin {name}", assembly.FullName);
+ Logger.LogDebug("Found API endpoints in plugin {Name}", assembly.FullName);
yield return assembly;
}
}
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 26fc1bee4..fb1bb65a0 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -890,7 +890,7 @@ namespace Emby.Server.Implementations.Channels
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error writing to channel cache file: {path}", path);
+ _logger.LogError(ex, "Error writing to channel cache file: {Path}", path);
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index f2c7118fe..57c1398e9 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -197,7 +197,7 @@ namespace Emby.Server.Implementations.Dto
catch (Exception ex)
{
// Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
- _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {itemName}", item.Name);
+ _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {ItemName}", item.Name);
}
}
diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs
index fe74f1de7..7435e9d0b 100644
--- a/Emby.Server.Implementations/IO/FileRefresher.cs
+++ b/Emby.Server.Implementations/IO/FileRefresher.cs
@@ -149,7 +149,7 @@ namespace Emby.Server.Implementations.IO
continue;
}
- _logger.LogInformation("{name} ({path}) will be refreshed.", item.Name, item.Path);
+ _logger.LogInformation("{Name} ({Path}) will be refreshed.", item.Name, item.Path);
try
{
@@ -160,11 +160,11 @@ namespace Emby.Server.Implementations.IO
// For now swallow and log.
// Research item: If an IOException occurs, the item may be in a disconnected state (media unavailable)
// Should we remove it from it's parent?
- _logger.LogError(ex, "Error refreshing {name}", item.Name);
+ _logger.LogError(ex, "Error refreshing {Name}", item.Name);
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error refreshing {name}", item.Name);
+ _logger.LogError(ex, "Error refreshing {Name}", item.Name);
}
}
}
@@ -214,6 +214,7 @@ namespace Emby.Server.Implementations.IO
}
}
+ ///
public void Dispose()
{
_disposed = true;
diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index 9290dfcd0..3353fae9d 100644
--- a/Emby.Server.Implementations/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -88,7 +88,7 @@ namespace Emby.Server.Implementations.IO
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error in ReportFileSystemChanged for {path}", path);
+ _logger.LogError(ex, "Error in ReportFileSystemChanged for {Path}", path);
}
}
}
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index ab6483bf9..3cb025111 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -398,30 +398,6 @@ namespace Emby.Server.Implementations.IO
}
}
- public virtual void SetReadOnly(string path, bool isReadOnly)
- {
- if (OperatingSystem.Id != OperatingSystemId.Windows)
- {
- return;
- }
-
- var info = GetExtendedFileSystemInfo(path);
-
- if (info.Exists && info.IsReadOnly != isReadOnly)
- {
- if (isReadOnly)
- {
- File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.ReadOnly);
- }
- else
- {
- var attributes = File.GetAttributes(path);
- attributes = RemoveAttribute(attributes, FileAttributes.ReadOnly);
- File.SetAttributes(path, attributes);
- }
- }
- }
-
public virtual void SetAttributes(string path, bool isHidden, bool isReadOnly)
{
if (OperatingSystem.Id != OperatingSystemId.Windows)
@@ -707,14 +683,6 @@ namespace Emby.Server.Implementations.IO
return Directory.EnumerateFileSystemEntries(path, "*", searchOption);
}
- public virtual void SetExecutable(string path)
- {
- if (OperatingSystem.Id == OperatingSystemId.Darwin)
- {
- RunProcess("chmod", "+x \"" + path + "\"", Path.GetDirectoryName(path));
- }
- }
-
private static void RunProcess(string path, string args, string workingDirectory)
{
using (var process = Process.Start(new ProcessStartInfo
diff --git a/Emby.Server.Implementations/IO/StreamHelper.cs b/Emby.Server.Implementations/IO/StreamHelper.cs
index 40b397edc..c16ebd61b 100644
--- a/Emby.Server.Implementations/IO/StreamHelper.cs
+++ b/Emby.Server.Implementations/IO/StreamHelper.cs
@@ -11,8 +11,6 @@ namespace Emby.Server.Implementations.IO
{
public class StreamHelper : IStreamHelper
{
- private const int StreamCopyToBufferSize = 81920;
-
public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken)
{
byte[] buffer = ArrayPool.Shared.Rent(bufferSize);
@@ -83,37 +81,9 @@ namespace Emby.Server.Implementations.IO
}
}
- public async Task CopyToAsync(Stream source, Stream destination, CancellationToken cancellationToken)
- {
- byte[] buffer = ArrayPool.Shared.Rent(StreamCopyToBufferSize);
- try
- {
- int totalBytesRead = 0;
-
- int bytesRead;
- while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
- {
- var bytesToWrite = bytesRead;
-
- if (bytesToWrite > 0)
- {
- await destination.WriteAsync(buffer, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
-
- totalBytesRead += bytesRead;
- }
- }
-
- return totalBytesRead;
- }
- finally
- {
- ArrayPool.Shared.Return(buffer);
- }
- }
-
public async Task CopyToAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
{
- byte[] buffer = ArrayPool.Shared.Rent(StreamCopyToBufferSize);
+ byte[] buffer = ArrayPool.Shared.Rent(IODefaults.CopyToBufferSize);
try
{
int bytesRead;
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
index 2e13a3bb3..0edd98031 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
@@ -52,10 +52,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.LogInformation("Copying recording stream to file {0}", targetFile);
// The media source is infinite so we need to handle stopping ourselves
- var durationToken = new CancellationTokenSource(duration);
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ using var durationToken = new CancellationTokenSource(duration);
+ using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token);
- await directStreamProvider.CopyToAsync(output, cancellationToken).ConfigureAwait(false);
+ await directStreamProvider.CopyToAsync(output, cancellationTokenSource.Token).ConfigureAwait(false);
}
_logger.LogInformation("Recording completed to file {0}", targetFile);
@@ -72,7 +72,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
UserAgent = "Emby/3.0",
// Shouldn't matter but may cause issues
- DecompressionMethod = CompressionMethods.None
+ DecompressionMethod = CompressionMethods.None,
+ CancellationToken = cancellationToken
};
using (var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false))
@@ -88,10 +89,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.LogInformation("Copying recording stream to file {0}", targetFile);
// The media source if infinite so we need to handle stopping ourselves
- var durationToken = new CancellationTokenSource(duration);
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ using var durationToken = new CancellationTokenSource(duration);
+ using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token);
- await _streamHelper.CopyUntilCancelled(response.Content, output, 81920, cancellationToken).ConfigureAwait(false);
+ await _streamHelper.CopyUntilCancelled(
+ response.Content,
+ output,
+ IODefaults.CopyToBufferSize,
+ cancellationTokenSource.Token).ConfigureAwait(false);
}
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 09c52d95b..5cf09b8e5 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -604,11 +604,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return Task.CompletedTask;
}
- public Task DeleteRecordingAsync(string recordingId, CancellationToken cancellationToken)
- {
- return Task.CompletedTask;
- }
-
public Task CreateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken)
{
throw new NotImplementedException();
@@ -808,11 +803,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
return null;
}
- public IEnumerable GetAllActiveRecordings()
- {
- return _activeRecordings.Values.Where(i => i.Timer.Status == RecordingStatus.InProgress && !i.CancellationTokenSource.IsCancellationRequested);
- }
-
public ActiveRecordingInfo GetActiveRecordingInfo(string path)
{
if (string.IsNullOrWhiteSpace(path))
@@ -1015,16 +1005,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
throw new Exception("Tuner not found.");
}
- private MediaSourceInfo CloneMediaSource(MediaSourceInfo mediaSource, bool enableStreamSharing)
- {
- var json = _jsonSerializer.SerializeToString(mediaSource);
- mediaSource = _jsonSerializer.DeserializeFromString(json);
-
- mediaSource.Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture) + "_" + mediaSource.Id;
-
- return mediaSource;
- }
-
public async Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(channelId))
@@ -1654,7 +1634,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
if (mediaSource.RequiresLooping || !(mediaSource.Container ?? string.Empty).EndsWith("ts", StringComparison.OrdinalIgnoreCase) || (mediaSource.Protocol != MediaProtocol.File && mediaSource.Protocol != MediaProtocol.Http))
{
- return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer, _config);
+ return new EncodedRecorder(_logger, _mediaEncoder, _config.ApplicationPaths, _jsonSerializer);
}
return new DirectRecorder(_logger, _httpClient, _streamHelper);
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 612dc5238..3e5457dbd 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -8,12 +8,9 @@ using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -26,26 +23,24 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private readonly ILogger _logger;
private readonly IMediaEncoder _mediaEncoder;
private readonly IServerApplicationPaths _appPaths;
+ private readonly IJsonSerializer _json;
+ private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource();
+
private bool _hasExited;
private Stream _logFileStream;
private string _targetPath;
private Process _process;
- private readonly IJsonSerializer _json;
- private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource();
- private readonly IServerConfigurationManager _config;
public EncodedRecorder(
ILogger logger,
IMediaEncoder mediaEncoder,
IServerApplicationPaths appPaths,
- IJsonSerializer json,
- IServerConfigurationManager config)
+ IJsonSerializer json)
{
_logger = logger;
_mediaEncoder = mediaEncoder;
_appPaths = appPaths;
_json = json;
- _config = config;
}
private static bool CopySubtitles => false;
@@ -58,19 +53,14 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
public async Task Record(IDirectStreamProvider directStreamProvider, MediaSourceInfo mediaSource, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
// The media source is infinite so we need to handle stopping ourselves
- var durationToken = new CancellationTokenSource(duration);
- cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token;
+ using var durationToken = new CancellationTokenSource(duration);
+ using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token);
- await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationToken).ConfigureAwait(false);
+ await RecordFromFile(mediaSource, mediaSource.Path, targetFile, duration, onStarted, cancellationTokenSource.Token).ConfigureAwait(false);
_logger.LogInformation("Recording completed to file {0}", targetFile);
}
- private EncodingOptions GetEncodingOptions()
- {
- return _config.GetConfiguration("encoding");
- }
-
private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken)
{
_targetPath = targetFile;
@@ -108,7 +98,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
StartInfo = processStartInfo,
EnableRaisingEvents = true
};
- _process.Exited += (sender, args) => OnFfMpegProcessExited(_process, inputFile);
+ _process.Exited += (sender, args) => OnFfMpegProcessExited(_process);
_process.Start();
@@ -221,20 +211,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
}
protected string GetOutputSizeParam()
- {
- var filters = new List();
-
- filters.Add("yadif=0:-1:0");
-
- var output = string.Empty;
-
- if (filters.Count > 0)
- {
- output += string.Format(CultureInfo.InvariantCulture, " -vf \"{0}\"", string.Join(",", filters.ToArray()));
- }
-
- return output;
- }
+ => "-vf \"yadif=0:-1:0\"";
private void Stop()
{
@@ -291,7 +268,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
///
/// Processes the exited.
///
- private void OnFfMpegProcessExited(Process process, string inputFile)
+ private void OnFfMpegProcessExited(Process process)
{
using (process)
{
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index c4d5cc58a..33331adaf 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -24,14 +24,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
public class SchedulesDirect : IListingsProvider
{
+ private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
+
private readonly ILogger _logger;
private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient;
private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
private readonly IApplicationHost _appHost;
- private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
-
public SchedulesDirect(
ILogger logger,
IJsonSerializer jsonSerializer,
@@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
while (start <= end)
{
- dates.Add(start.ToString("yyyy-MM-dd"));
+ dates.Add(start.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
start = start.AddDays(1);
}
@@ -367,13 +367,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
if (!string.IsNullOrWhiteSpace(details.originalAirDate))
{
- info.OriginalAirDate = DateTime.Parse(details.originalAirDate);
+ info.OriginalAirDate = DateTime.Parse(details.originalAirDate, CultureInfo.InvariantCulture);
info.ProductionYear = info.OriginalAirDate.Value.Year;
}
if (details.movie != null)
{
- if (!string.IsNullOrEmpty(details.movie.year) && int.TryParse(details.movie.year, out int year))
+ if (!string.IsNullOrEmpty(details.movie.year)
+ && int.TryParse(details.movie.year, out int year))
{
info.ProductionYear = year;
}
@@ -587,7 +588,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return null;
}
- NameValuePair savedToken = null;
+ NameValuePair savedToken;
if (!_tokens.TryGetValue(username, out savedToken))
{
savedToken = new NameValuePair();
@@ -633,7 +634,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
}
}
- private async Task Post(HttpRequestOptions options,
+ private async Task Post(
+ HttpRequestOptions options,
bool enableRetry,
ListingsProviderInfo providerInfo)
{
@@ -663,7 +665,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return await Post(options, false, providerInfo).ConfigureAwait(false);
}
- private async Task Get(HttpRequestOptions options,
+ private async Task Get(
+ HttpRequestOptions options,
bool enableRetry,
ListingsProviderInfo providerInfo)
{
@@ -693,7 +696,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return await Get(options, false, providerInfo).ConfigureAwait(false);
}
- private async Task GetTokenInternal(string username, string password,
+ private async Task GetTokenInternal(
+ string username,
+ string password,
CancellationToken cancellationToken)
{
var httpOptions = new HttpRequestOptions()
diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json
index d4341f2e8..a97c2e17a 100644
--- a/Emby.Server.Implementations/Localization/Core/nb.json
+++ b/Emby.Server.Implementations/Localization/Core/nb.json
@@ -71,7 +71,7 @@
"ScheduledTaskFailedWithName": "{0} mislykkes",
"ScheduledTaskStartedWithName": "{0} startet",
"ServerNameNeedsToBeRestarted": "{0} må startes på nytt",
- "Shows": "Programmer",
+ "Shows": "Program",
"Songs": "Sanger",
"StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
"SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for {0}",
@@ -88,7 +88,7 @@
"UserOnlineFromDevice": "{0} er tilkoblet fra {1}",
"UserPasswordChangedWithName": "Passordet for {0} er oppdatert",
"UserPolicyUpdatedWithName": "Brukerpolicyen har blitt oppdatert for {0}",
- "UserStartedPlayingItemWithValues": "{0} har startet avspilling {1}",
+ "UserStartedPlayingItemWithValues": "{0} har startet avspilling {1} på {2}",
"UserStoppedPlayingItemWithValues": "{0} har stoppet avspilling {1}",
"ValueHasBeenAddedToLibrary": "{0} har blitt lagt til i mediebiblioteket ditt",
"ValueSpecialEpisodeName": "Spesialepisode - {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/nn.json b/Emby.Server.Implementations/Localization/Core/nn.json
index 281cadac5..fb6e81beb 100644
--- a/Emby.Server.Implementations/Localization/Core/nn.json
+++ b/Emby.Server.Implementations/Localization/Core/nn.json
@@ -35,7 +35,7 @@
"AuthenticationSucceededWithUserName": "{0} Har logga inn",
"Artists": "Artistar",
"Application": "Program",
- "AppDeviceValues": "App: {0}, Einheit: {1}",
+ "AppDeviceValues": "App: {0}, Eining: {1}",
"Albums": "Album",
"NotificationOptionServerRestartRequired": "Tenaren krev omstart",
"NotificationOptionPluginUpdateInstalled": "Tilleggsprogram-oppdatering vart installert",
@@ -43,7 +43,7 @@
"NotificationOptionPluginInstalled": "Tilleggsprogram installert",
"NotificationOptionPluginError": "Tilleggsprogram feila",
"NotificationOptionNewLibraryContent": "Nytt innhald er lagt til",
- "NotificationOptionInstallationFailed": "Installasjonen feila",
+ "NotificationOptionInstallationFailed": "Installasjonsfeil",
"NotificationOptionCameraImageUploaded": "Kamerabilde vart lasta opp",
"NotificationOptionAudioPlaybackStopped": "Lydavspilling stoppa",
"NotificationOptionAudioPlayback": "Lydavspilling påbyrja",
@@ -56,5 +56,62 @@
"MusicVideos": "Musikkvideoar",
"Music": "Musikk",
"Movies": "Filmar",
- "MixedContent": "Blanda innhald"
+ "MixedContent": "Blanda innhald",
+ "Sync": "Synkronisera",
+ "TaskDownloadMissingSubtitlesDescription": "Søk Internettet for manglande undertekstar basert på metadatainnstillingar.",
+ "TaskDownloadMissingSubtitles": "Last ned manglande undertekstar",
+ "TaskRefreshChannelsDescription": "Oppdater internettkanalinformasjon.",
+ "TaskRefreshChannels": "Oppdater kanalar",
+ "TaskCleanTranscodeDescription": "Slett transkodefiler som er meir enn ein dag gamal.",
+ "TaskCleanTranscode": "Reins transkodemappe",
+ "TaskUpdatePluginsDescription": "Laster ned og installerer oppdateringar for programtillegg som er sette opp til å oppdaterast automatisk.",
+ "TaskUpdatePlugins": "Oppdaterer programtillegg",
+ "TaskRefreshPeopleDescription": "Oppdaterer metadata for skodespelarar og regissørar i mediebiblioteket ditt.",
+ "TaskRefreshPeople": "Oppdater personar",
+ "TaskCleanLogsDescription": "Slett loggfiler som er meir enn {0} dagar gamle.",
+ "TaskCleanLogs": "Reins loggmappe",
+ "TaskRefreshLibraryDescription": "Skannar mediebiblioteket ditt for nye filer og oppdaterer metadata.",
+ "TaskRefreshLibrary": "Skann mediebibliotek",
+ "TaskRefreshChapterImagesDescription": "Lager miniatyrbilete for videoar som har kapittel.",
+ "TaskRefreshChapterImages": "Trekk ut kapittelbilete",
+ "TaskCleanCacheDescription": "Slettar mellomlagra filer som ikkje lengre trengst av systemet.",
+ "TaskCleanCache": "Rens mappe for hurtiglager",
+ "TasksChannelsCategory": "Internettkanalar",
+ "TasksApplicationCategory": "Applikasjon",
+ "TasksLibraryCategory": "Bibliotek",
+ "TasksMaintenanceCategory": "Vedlikehald",
+ "VersionNumber": "Versjon {0}",
+ "ValueSpecialEpisodeName": "Spesialepisode - {0}",
+ "ValueHasBeenAddedToLibrary": "{0} har blitt lagt til i mediebiblioteket ditt",
+ "UserStoppedPlayingItemWithValues": "{0} har fullført avspeling {1} på {2}",
+ "UserStartedPlayingItemWithValues": "{0} spelar {1} på {2}",
+ "UserPolicyUpdatedWithName": "Brukarreglar har blitt oppdatert for {0}",
+ "UserPasswordChangedWithName": "Passordet for {0} er oppdatert",
+ "UserOnlineFromDevice": "{0} er direktekopla frå {1}",
+ "UserOfflineFromDevice": "{0} har kopla frå {1}",
+ "UserLockedOutWithName": "Brukar {0} har blitt utestengd",
+ "UserDownloadingItemWithValues": "{0} lastar ned {1}",
+ "UserDeletedWithName": "Brukar {0} er sletta",
+ "UserCreatedWithName": "Brukar {0} er oppretta",
+ "User": "Brukar",
+ "TvShows": "TV-seriar",
+ "System": "System",
+ "SubtitleDownloadFailureFromForItem": "Feila å laste ned undertekstar frå {0} for {1}",
+ "StartupEmbyServerIsLoading": "Jellyfintenaren laster. Prøv igjen om litt.",
+ "Songs": "Songar",
+ "Shows": "Program",
+ "ServerNameNeedsToBeRestarted": "{0} må omstartast",
+ "ScheduledTaskStartedWithName": "{0} starta",
+ "ScheduledTaskFailedWithName": "{0} feila",
+ "ProviderValue": "Leverandør: {0}",
+ "PluginUpdatedWithName": "{0} blei oppdatert",
+ "PluginUninstalledWithName": "{0} blei avinstallert",
+ "PluginInstalledWithName": "{0} blei installert",
+ "Plugin": "Programtillegg",
+ "Playlists": "Speleliste",
+ "Photos": "Foto",
+ "NotificationOptionVideoPlaybackStopped": "Videoavspeling stoppa",
+ "NotificationOptionVideoPlayback": "Videoavspeling starta",
+ "NotificationOptionUserLockedOut": "Brukar er utestengd",
+ "NotificationOptionTaskFailed": "Planlagt oppgåve feila"
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index e29fcfb5f..5adcefc1f 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -5,10 +5,10 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
+using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
-using MediaBrowser.Model.Globalization;
namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
@@ -21,10 +21,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// Gets or sets the application paths.
///
/// The application paths.
- private IApplicationPaths ApplicationPaths { get; set; }
-
+ private readonly IApplicationPaths _applicationPaths;
private readonly ILogger _logger;
-
private readonly IFileSystem _fileSystem;
private readonly ILocalizationManager _localization;
@@ -37,20 +35,41 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
IFileSystem fileSystem,
ILocalizationManager localization)
{
- ApplicationPaths = appPaths;
+ _applicationPaths = appPaths;
_logger = logger;
_fileSystem = fileSystem;
_localization = localization;
}
+ ///
+ public string Name => _localization.GetLocalizedString("TaskCleanCache");
+
+ ///
+ public string Description => _localization.GetLocalizedString("TaskCleanCacheDescription");
+
+ ///
+ public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+ ///
+ public string Key => "DeleteCacheFiles";
+
+ ///
+ public bool IsHidden => false;
+
+ ///
+ public bool IsEnabled => true;
+
+ ///
+ public bool IsLogged => true;
+
///
/// Creates the triggers that define when the task will run.
///
/// IEnumerable{BaseTaskTrigger}.
public IEnumerable GetDefaultTriggers()
{
- return new[] {
-
+ return new[]
+ {
// Every so often
new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks}
};
@@ -68,7 +87,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try
{
- DeleteCacheFilesFromDirectory(cancellationToken, ApplicationPaths.CachePath, minDateModified, progress);
+ DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.CachePath, minDateModified, progress);
}
catch (DirectoryNotFoundException)
{
@@ -81,7 +100,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try
{
- DeleteCacheFilesFromDirectory(cancellationToken, ApplicationPaths.TempDirectory, minDateModified, progress);
+ DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.TempDirectory, minDateModified, progress);
}
catch (DirectoryNotFoundException)
{
@@ -91,7 +110,6 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
return Task.CompletedTask;
}
-
///
/// Deletes the cache files from directory with a last write time less than a given date.
///
@@ -164,26 +182,5 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
_logger.LogError(ex, "Error deleting file {path}", path);
}
}
-
- ///
- public string Name => _localization.GetLocalizedString("TaskCleanCache");
-
- ///
- public string Description => _localization.GetLocalizedString("TaskCleanCacheDescription");
-
- ///
- public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
-
- ///
- public string Key => "DeleteCacheFiles";
-
- ///
- public bool IsHidden => false;
-
- ///
- public bool IsEnabled => true;
-
- ///
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
index 7388086fb..c5af68bce 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs
@@ -34,6 +34,27 @@ namespace Emby.Server.Implementations.ScheduledTasks
_localization = localization;
}
+ ///
+ public string Name => _localization.GetLocalizedString("TaskUpdatePlugins");
+
+ ///
+ public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription");
+
+ ///
+ public string Category => _localization.GetLocalizedString("TasksApplicationCategory");
+
+ ///
+ public string Key => "PluginUpdates";
+
+ ///
+ public bool IsHidden => false;
+
+ ///
+ public bool IsEnabled => true;
+
+ ///
+ public bool IsLogged => true;
+
///
/// Creates the triggers that define when the task will run.
///
@@ -98,26 +119,5 @@ namespace Emby.Server.Implementations.ScheduledTasks
progress.Report(100);
}
-
- ///
- public string Name => _localization.GetLocalizedString("TaskUpdatePlugins");
-
- ///
- public string Description => _localization.GetLocalizedString("TaskUpdatePluginsDescription");
-
- ///
- public string Category => _localization.GetLocalizedString("TasksApplicationCategory");
-
- ///
- public string Key => "PluginUpdates";
-
- ///
- public bool IsHidden => false;
-
- ///
- public bool IsEnabled => true;
-
- ///
- public bool IsLogged => true;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
index eb628ec5f..8b67d37d7 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
@@ -11,7 +11,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
public class DailyTrigger : ITaskTrigger
{
///
- /// Get the time of day to trigger the task to run.
+ /// Occurs when [triggered].
+ ///
+ public event EventHandler Triggered;
+
+ ///
+ /// Gets or sets the time of day to trigger the task to run.
///
/// The time of day.
public TimeSpan TimeOfDay { get; set; }
@@ -69,11 +74,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
}
- ///
- /// Occurs when [triggered].
- ///
- public event EventHandler Triggered;
-
///
/// Called when [triggered].
///
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
index 247a6785a..b04fd7c7e 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
@@ -11,6 +11,13 @@ namespace Emby.Server.Implementations.ScheduledTasks
///
public class IntervalTrigger : ITaskTrigger
{
+ private DateTime _lastStartDate;
+
+ ///
+ /// Occurs when [triggered].
+ ///
+ public event EventHandler Triggered;
+
///
/// Gets or sets the interval.
///
@@ -28,8 +35,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// The timer.
private Timer Timer { get; set; }
- private DateTime _lastStartDate;
-
///
/// Stars waiting for the trigger action.
///
@@ -88,11 +93,6 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
}
- ///
- /// Occurs when [triggered].
- ///
- public event EventHandler Triggered;
-
///
/// Called when [triggered].
///
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
index 96e5d8897..7cd5493da 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
@@ -12,6 +12,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
///
public class StartupTrigger : ITaskTrigger
{
+ ///
+ /// Occurs when [triggered].
+ ///
+ public event EventHandler Triggered;
+
public int DelayMs { get; set; }
///
@@ -48,20 +53,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
{
}
- ///
- /// Occurs when [triggered].
- ///
- public event EventHandler Triggered;
-
///
/// Called when [triggered].
///
private void OnTriggered()
{
- if (Triggered != null)
- {
- Triggered(this, EventArgs.Empty);
- }
+ Triggered?.Invoke(this, EventArgs.Empty);
}
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
index 4f1bf5c19..0c0ebec08 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
@@ -11,7 +11,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
public class WeeklyTrigger : ITaskTrigger
{
///
- /// Get the time of day to trigger the task to run.
+ /// Occurs when [triggered].
+ ///
+ public event EventHandler Triggered;
+
+ ///
+ /// Gets or sets the time of day to trigger the task to run.
///
/// The time of day.
public TimeSpan TimeOfDay { get; set; }
@@ -95,20 +100,12 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
}
- ///
- /// Occurs when [triggered].
- ///
- public event EventHandler Triggered;
-
///
/// Called when [triggered].
///
private void OnTriggered()
{
- if (Triggered != null)
- {
- Triggered(this, EventArgs.Empty);
- }
+ Triggered?.Invoke(this, EventArgs.Empty);
}
}
}
diff --git a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
index c547d0cde..c3b67eec3 100644
--- a/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
+++ b/Jellyfin.Api/Controllers/DisplayPreferencesController.cs
@@ -153,7 +153,6 @@ namespace Jellyfin.Api.Controllers
{
var itemPreferences = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Parse(key.Substring("landing-".Length)), existingDisplayPreferences.Client);
itemPreferences.ViewType = Enum.Parse(displayPreferences.ViewType);
- _displayPreferencesManager.SaveChanges(itemPreferences);
}
var itemPrefs = _displayPreferencesManager.GetItemDisplayPreferences(existingDisplayPreferences.UserId, Guid.Empty, existingDisplayPreferences.Client);
@@ -167,8 +166,7 @@ namespace Jellyfin.Api.Controllers
itemPrefs.ViewType = viewType;
}
- _displayPreferencesManager.SaveChanges(existingDisplayPreferences);
- _displayPreferencesManager.SaveChanges(itemPrefs);
+ _displayPreferencesManager.SaveChanges();
return NoContent();
}
diff --git a/Jellyfin.Api/Controllers/DlnaServerController.cs b/Jellyfin.Api/Controllers/DlnaServerController.cs
index d6ca2a611..fc2552009 100644
--- a/Jellyfin.Api/Controllers/DlnaServerController.cs
+++ b/Jellyfin.Api/Controllers/DlnaServerController.cs
@@ -65,6 +65,8 @@ namespace Jellyfin.Api.Controllers
[HttpGet("{serverId}/ContentDirectory.xml", Name = "GetContentDirectory_2")]
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
+ [HttpGet("{serverId}/ContentDirectory/ContentDirectory", Name = "GetContentDirectory_2")]
+ [HttpGet("{serverId}/ContentDirectory/ContentDirectory.xml", Name = "GetContentDirectory_3")]
[ProducesResponseType(StatusCodes.Status200OK)]
[SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
public ActionResult GetContentDirectory([FromRoute] string serverId)
@@ -77,8 +79,8 @@ namespace Jellyfin.Api.Controllers
///
/// Server UUID.
/// Dlna media receiver registrar xml.
- [HttpGet("{serverId}/MediaReceiverRegistrar")]
- [HttpGet("{serverId}/MediaReceiverRegistrar.xml", Name = "GetMediaReceiverRegistrar_2")]
+ [HttpGet("{serverId}/MediaReceiverRegistrar/MediaReceiverRegistrar", Name = "GetMediaReceiverRegistrar_2")]
+ [HttpGet("{serverId}/MediaReceiverRegistrar/MediaReceiverRegistrar.xml", Name = "GetMediaReceiverRegistrar_3")]
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -94,7 +96,8 @@ namespace Jellyfin.Api.Controllers
/// Server UUID.
/// Dlna media receiver registrar xml.
[HttpGet("{serverId}/ConnectionManager")]
- [HttpGet("{serverId}/ConnectionManager.xml", Name = "GetConnectionManager_2")]
+ [HttpGet("{serverId}/ConnectionManager/ConnectionManager", Name = "GetConnectionManager_2")]
+ [HttpGet("{serverId}/ConnectionManager/ConnectionManager.xml", Name = "GetConnectionManager_3")]
[Produces(MediaTypeNames.Text.Xml)]
[ProducesFile(MediaTypeNames.Text.Xml)]
[ProducesResponseType(StatusCodes.Status200OK)]
diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs
index 230bb8295..759a574b8 100644
--- a/Jellyfin.Api/Controllers/DynamicHlsController.cs
+++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs
@@ -1361,15 +1361,20 @@ namespace Jellyfin.Api.Controllers
segmentFormat = "mpegts";
}
+ var maxMuxingQueueSize = encodingOptions.MaxMuxingQueueSize > 128
+ ? encodingOptions.MaxMuxingQueueSize.ToString(CultureInfo.InvariantCulture)
+ : "128";
+
return string.Format(
CultureInfo.InvariantCulture,
- "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size 2048 -f hls -max_delay 5000000 -hls_time {6} -individual_header_trailer 0 -hls_segment_type {7} -start_number {8} -hls_segment_filename \"{9}\" -hls_playlist_type vod -hls_list_size 0 -y \"{10}\"",
+ "{0} {1} -map_metadata -1 -map_chapters -1 -threads {2} {3} {4} {5} -copyts -avoid_negative_ts disabled -max_muxing_queue_size {6} -f hls -max_delay 5000000 -hls_time {7} -individual_header_trailer 0 -hls_segment_type {8} -start_number {9} -hls_segment_filename \"{10}\" -hls_playlist_type vod -hls_list_size 0 -y \"{11}\"",
inputModifier,
_encodingHelper.GetInputArgument(state, encodingOptions),
threads,
mapArgs,
GetVideoArguments(state, encodingOptions, startNumber),
GetAudioArguments(state, encodingOptions),
+ maxMuxingQueueSize,
state.SegmentLength.ToString(CultureInfo.InvariantCulture),
segmentFormat,
startNumberParam,
diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
index 7c5c5a3ec..46f1c618f 100644
--- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
+++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
@@ -14,22 +14,21 @@ namespace Jellyfin.Server.Implementations.Users
///
public class DisplayPreferencesManager : IDisplayPreferencesManager
{
- private readonly JellyfinDbProvider _dbProvider;
+ private readonly JellyfinDb _dbContext;
///
/// Initializes a new instance of the class.
///
- /// The Jellyfin db provider.
- public DisplayPreferencesManager(JellyfinDbProvider dbProvider)
+ /// The database context.
+ public DisplayPreferencesManager(JellyfinDb dbContext)
{
- _dbProvider = dbProvider;
+ _dbContext = dbContext;
}
///
public DisplayPreferences GetDisplayPreferences(Guid userId, string client)
{
- using var dbContext = _dbProvider.CreateContext();
- var prefs = dbContext.DisplayPreferences
+ var prefs = _dbContext.DisplayPreferences
.Include(pref => pref.HomeSections)
.FirstOrDefault(pref =>
pref.UserId == userId && string.Equals(pref.Client, client));
@@ -37,7 +36,7 @@ namespace Jellyfin.Server.Implementations.Users
if (prefs == null)
{
prefs = new DisplayPreferences(userId, client);
- dbContext.DisplayPreferences.Add(prefs);
+ _dbContext.DisplayPreferences.Add(prefs);
}
return prefs;
@@ -46,14 +45,13 @@ namespace Jellyfin.Server.Implementations.Users
///
public ItemDisplayPreferences GetItemDisplayPreferences(Guid userId, Guid itemId, string client)
{
- using var dbContext = _dbProvider.CreateContext();
- var prefs = dbContext.ItemDisplayPreferences
+ var prefs = _dbContext.ItemDisplayPreferences
.FirstOrDefault(pref => pref.UserId == userId && pref.ItemId == itemId && string.Equals(pref.Client, client));
if (prefs == null)
{
prefs = new ItemDisplayPreferences(userId, Guid.Empty, client);
- dbContext.ItemDisplayPreferences.Add(prefs);
+ _dbContext.ItemDisplayPreferences.Add(prefs);
}
return prefs;
@@ -62,27 +60,15 @@ namespace Jellyfin.Server.Implementations.Users
///
public IList ListItemDisplayPreferences(Guid userId, string client)
{
- using var dbContext = _dbProvider.CreateContext();
-
- return dbContext.ItemDisplayPreferences
+ return _dbContext.ItemDisplayPreferences
.Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client))
.ToList();
}
///
- public void SaveChanges(DisplayPreferences preferences)
+ public void SaveChanges()
{
- using var dbContext = _dbProvider.CreateContext();
- dbContext.Update(preferences);
- dbContext.SaveChanges();
- }
-
- ///
- public void SaveChanges(ItemDisplayPreferences preferences)
- {
- using var dbContext = _dbProvider.CreateContext();
- dbContext.Update(preferences);
- dbContext.SaveChanges();
+ _dbContext.SaveChanges();
}
}
}
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index 755844dd9..8d569a779 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Reflection;
using Emby.Drawing;
using Emby.Server.Implementations;
@@ -15,6 +16,7 @@ using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.IO;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -67,12 +69,8 @@ namespace Jellyfin.Server
Logger.LogWarning($"Skia not available. Will fallback to {nameof(NullImageEncoder)}.");
}
- // TODO: Set up scoping and use AddDbContextPool,
- // can't register as Transient since tracking transient in GC is funky
- // serviceCollection.AddDbContext(
- // options => options
- // .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"),
- // ServiceLifetime.Transient);
+ ServiceCollection.AddDbContextPool(
+ options => options.UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"));
ServiceCollection.AddEventServices();
ServiceCollection.AddSingleton();
diff --git a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs
index 71c66a310..2b002c6f3 100644
--- a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs
@@ -39,12 +39,14 @@ namespace Jellyfin.Server.Extensions
c.DocumentTitle = "Jellyfin API";
c.SwaggerEndpoint($"/{baseUrl}api-docs/openapi.json", "Jellyfin API");
c.RoutePrefix = $"{baseUrl}api-docs/swagger";
+ c.InjectStylesheet($"/{baseUrl}api-docs/swagger/custom.css");
})
.UseReDoc(c =>
{
c.DocumentTitle = "Jellyfin API";
c.SpecUrl($"/{baseUrl}api-docs/openapi.json");
c.RoutePrefix = $"{baseUrl}api-docs/redoc";
+ c.InjectStylesheet($"/{baseUrl}api-docs/redoc/custom.css");
});
}
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 6ca370d04..24ba8369a 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -64,4 +64,13 @@
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs
index 9e456de12..1a34de269 100644
--- a/Jellyfin.Server/Startup.cs
+++ b/Jellyfin.Server/Startup.cs
@@ -112,6 +112,7 @@ namespace Jellyfin.Server
app.UseHttpsRedirection();
}
+ app.UseStaticFiles();
app.UseAuthentication();
app.UseJellyfinApiSwagger(_serverConfigurationManager);
app.UseRouting();
diff --git a/Jellyfin.Server/wwwroot/api-docs/redoc/custom.css b/Jellyfin.Server/wwwroot/api-docs/redoc/custom.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/Jellyfin.Server/wwwroot/api-docs/swagger/custom.css b/Jellyfin.Server/wwwroot/api-docs/swagger/custom.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/MediaBrowser.Controller/IDisplayPreferencesManager.cs b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
index 856b91b5d..b35f83096 100644
--- a/MediaBrowser.Controller/IDisplayPreferencesManager.cs
+++ b/MediaBrowser.Controller/IDisplayPreferencesManager.cs
@@ -35,15 +35,8 @@ namespace MediaBrowser.Controller
IList ListItemDisplayPreferences(Guid userId, string client);
///
- /// Saves changes to the provided display preferences.
+ /// Saves changes made to the database.
///
- /// The display preferences to save.
- void SaveChanges(DisplayPreferences preferences);
-
- ///
- /// Saves changes to the provided item display preferences.
- ///
- /// The item display preferences to save.
- void SaveChanges(ItemDisplayPreferences preferences);
+ void SaveChanges();
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
index d7afd2118..44bd38b54 100644
--- a/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
+++ b/MediaBrowser.Controller/LiveTv/ChannelInfo.cs
@@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.LiveTv
///
/// null if [has image] contains no value, true if [has image]; otherwise, false.
public bool? HasImage { get; set; }
+
///
/// Gets or sets a value indicating whether this instance is favorite.
///
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 550916f82..9f6b2be8f 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -2090,6 +2090,9 @@ namespace MediaBrowser.Controller.MediaEncoding
var hasTextSubs = state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
+ // If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
+ var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
+
// When the input may or may not be hardware VAAPI decodable
if (isVaapiH264Encoder)
{
@@ -2136,35 +2139,38 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (isVaapiH264Encoder)
{
- filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi"));
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "deinterlace_vaapi=rate={0}",
+ doubleRateDeinterlace ? "field" : "frame"));
}
}
// Add software deinterlace filter before scaling filter
- if (state.DeInterlace("h264", true)
- || state.DeInterlace("avc", true)
- || state.DeInterlace("h265", true)
- || state.DeInterlace("hevc", true))
+ if ((state.DeInterlace("h264", true)
+ || state.DeInterlace("avc", true)
+ || state.DeInterlace("h265", true)
+ || state.DeInterlace("hevc", true))
+ && !isVaapiH264Encoder
+ && !isQsvH264Encoder
+ && !isNvdecH264Decoder)
{
- string deintParam;
- var inputFramerate = videoStream?.RealFrameRate;
-
- // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
- if (string.Equals(options.DeinterlaceMethod, "yadif_bob", StringComparison.OrdinalIgnoreCase) && (inputFramerate ?? 60) <= 30)
+ if (string.Equals(options.DeinterlaceMethod, "bwdif", StringComparison.OrdinalIgnoreCase))
{
- deintParam = "yadif=1:-1:0";
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "bwdif={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
}
else
{
- deintParam = "yadif=0:-1:0";
- }
-
- if (!string.IsNullOrEmpty(deintParam))
- {
- if (!isVaapiH264Encoder && !isQsvH264Encoder && !isNvdecH264Decoder)
- {
- filters.Add(deintParam);
- }
+ filters.Add(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "yadif={0}:-1:0",
+ doubleRateDeinterlace ? "1" : "0"));
}
}
@@ -2397,6 +2403,11 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.DeInterlace("h264", true))
{
inputModifier += " -deint 1";
+
+ if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.RealFrameRate ?? 60) > 30)
+ {
+ inputModifier += " -drop_second_field 1";
+ }
}
}
}
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index 9a30f7e9f..41ff517a0 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -11,6 +11,8 @@ namespace MediaBrowser.Model.Configuration
public double DownMixAudioBoost { get; set; }
+ public int MaxMuxingQueueSize { get; set; }
+
public bool EnableThrottling { get; set; }
public int ThrottleDelaySeconds { get; set; }
@@ -35,6 +37,8 @@ namespace MediaBrowser.Model.Configuration
public string EncoderPreset { get; set; }
+ public bool DeinterlaceDoubleRate { get; set; }
+
public string DeinterlaceMethod { get; set; }
public bool EnableDecodingColorDepth10Hevc { get; set; }
@@ -50,6 +54,7 @@ namespace MediaBrowser.Model.Configuration
public EncodingOptions()
{
DownMixAudioBoost = 2;
+ MaxMuxingQueueSize = 2048;
EnableThrottling = false;
ThrottleDelaySeconds = 180;
EncodingThreadCount = -1;
@@ -57,6 +62,7 @@ namespace MediaBrowser.Model.Configuration
VaapiDevice = "/dev/dri/renderD128";
H264Crf = 23;
H265Crf = 28;
+ DeinterlaceDoubleRate = false;
DeinterlaceMethod = "yadif";
EnableDecodingColorDepth10Hevc = true;
EnableDecodingColorDepth10Vp9 = true;
diff --git a/MediaBrowser.Model/IO/FileSystemMetadata.cs b/MediaBrowser.Model/IO/FileSystemMetadata.cs
index b23119d08..118c78e80 100644
--- a/MediaBrowser.Model/IO/FileSystemMetadata.cs
+++ b/MediaBrowser.Model/IO/FileSystemMetadata.cs
@@ -56,7 +56,7 @@ namespace MediaBrowser.Model.IO
public DateTime CreationTimeUtc { get; set; }
///
- /// Gets a value indicating whether this instance is directory.
+ /// Gets or sets a value indicating whether this instance is directory.
///
/// true if this instance is directory; otherwise, false.
public bool IsDirectory { get; set; }
diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs
index bba69d4b4..dc6549787 100644
--- a/MediaBrowser.Model/IO/IFileSystem.cs
+++ b/MediaBrowser.Model/IO/IFileSystem.cs
@@ -201,9 +201,9 @@ namespace MediaBrowser.Model.IO
IEnumerable GetFileSystemEntryPaths(string path, bool recursive = false);
void SetHidden(string path, bool isHidden);
- void SetReadOnly(string path, bool readOnly);
+
void SetAttributes(string path, bool isHidden, bool readOnly);
+
List GetDrives();
- void SetExecutable(string path);
}
}
diff --git a/MediaBrowser.Model/IO/IShortcutHandler.cs b/MediaBrowser.Model/IO/IShortcutHandler.cs
index 5c663aa0d..14d5c4b62 100644
--- a/MediaBrowser.Model/IO/IShortcutHandler.cs
+++ b/MediaBrowser.Model/IO/IShortcutHandler.cs
@@ -22,7 +22,6 @@ namespace MediaBrowser.Model.IO
///
/// The shortcut path.
/// The target path.
- /// System.String.
void Create(string shortcutPath, string targetPath);
}
}
diff --git a/MediaBrowser.Model/IO/IStreamHelper.cs b/MediaBrowser.Model/IO/IStreamHelper.cs
index af5ba5b17..0e09db16e 100644
--- a/MediaBrowser.Model/IO/IStreamHelper.cs
+++ b/MediaBrowser.Model/IO/IStreamHelper.cs
@@ -13,8 +13,6 @@ namespace MediaBrowser.Model.IO
Task CopyToAsync(Stream source, Stream destination, int bufferSize, int emptyReadLimit, CancellationToken cancellationToken);
- Task CopyToAsync(Stream source, Stream destination, CancellationToken cancellationToken);
-
Task CopyToAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken);
Task CopyUntilCancelled(Stream source, Stream target, int bufferSize, CancellationToken cancellationToken);
diff --git a/MediaBrowser.Model/IO/IZipClient.cs b/MediaBrowser.Model/IO/IZipClient.cs
index 2daa54f22..fca52ebae 100644
--- a/MediaBrowser.Model/IO/IZipClient.cs
+++ b/MediaBrowser.Model/IO/IZipClient.cs
@@ -26,6 +26,7 @@ namespace MediaBrowser.Model.IO
void ExtractAll(Stream source, string targetPath, bool overwriteExistingFiles);
void ExtractAllFromGz(Stream source, string targetPath, bool overwriteExistingFiles);
+
void ExtractFirstFileFromGz(Stream source, string targetPath, string defaultFileName);
///
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
index f31a7faea..291b36027 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonImageProvider.cs
@@ -31,9 +31,13 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
_httpClientFactory = httpClientFactory;
}
+ public static string ProviderName => TmdbUtils.ProviderName;
+
+ ///
public string Name => ProviderName;
- public static string ProviderName => TmdbUtils.ProviderName;
+ ///
+ public int Order => 0;
public bool Supports(BaseItem item)
{
@@ -125,8 +129,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
return profile.Iso_639_1?.ToString();
}
- public int Order => 0;
-
public Task GetImageResponse(string url, CancellationToken cancellationToken)
{
return _httpClientFactory.CreateClient().GetAsync(url, cancellationToken);
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
index e9fb5c703..a4b1387d3 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/People/TmdbPersonProvider.cs
@@ -32,7 +32,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
{
const string DataFileName = "info.json";
- internal static TmdbPersonProvider Current { get; private set; }
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private readonly IJsonSerializer _jsonSerializer;
private readonly IFileSystem _fileSystem;
@@ -55,6 +55,8 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
Current = this;
}
+ internal static TmdbPersonProvider Current { get; private set; }
+
public string Name => TmdbUtils.ProviderName;
public async Task> GetSearchResults(PersonLookupInfo searchInfo, CancellationToken cancellationToken)
@@ -95,7 +97,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
return new List();
}
- var url = string.Format(TmdbUtils.BaseTmdbApiUrl + @"3/search/person?api_key={1}&query={0}", WebUtility.UrlEncode(searchInfo.Name), TmdbUtils.ApiKey);
+ var url = string.Format(
+ CultureInfo.InvariantCulture,
+ TmdbUtils.BaseTmdbApiUrl + @"3/search/person?api_key={1}&query={0}",
+ WebUtility.UrlEncode(searchInfo.Name),
+ TmdbUtils.ApiKey);
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var header in TmdbUtils.AcceptHeaders)
@@ -200,8 +206,6 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
return result;
}
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
///
/// Gets the TMDB id.
///
@@ -226,7 +230,11 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
return;
}
- var url = string.Format(TmdbUtils.BaseTmdbApiUrl + @"3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids", TmdbUtils.ApiKey, id);
+ var url = string.Format(
+ CultureInfo.InvariantCulture,
+ TmdbUtils.BaseTmdbApiUrl + @"3/person/{1}?api_key={0}&append_to_response=credits,images,external_ids",
+ TmdbUtils.ApiKey,
+ id);
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var header in TmdbUtils.AcceptHeaders)
diff --git a/debian/rules b/debian/rules
index 2a5d41a69..6c7fbb779 100755
--- a/debian/rules
+++ b/debian/rules
@@ -40,7 +40,7 @@ override_dh_clistrip:
override_dh_auto_build:
dotnet publish --configuration $(CONFIG) --output='$(CURDIR)/usr/lib/jellyfin/bin' --self-contained --runtime $(DOTNETRUNTIME) \
- "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none" Jellyfin.Server
+ "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none" Jellyfin.Server
override_dh_auto_clean:
dotnet clean -maxcpucount:1 --configuration $(CONFIG) Jellyfin.Server || true
diff --git a/deployment/Dockerfile.docker.amd64 b/deployment/Dockerfile.docker.amd64
index 204ded3a4..cf0901404 100644
--- a/deployment/Dockerfile.docker.amd64
+++ b/deployment/Dockerfile.docker.amd64
@@ -12,4 +12,4 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
-RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-x64 "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none"
diff --git a/deployment/Dockerfile.docker.arm64 b/deployment/Dockerfile.docker.arm64
index eedbaac33..5454ef024 100644
--- a/deployment/Dockerfile.docker.arm64
+++ b/deployment/Dockerfile.docker.arm64
@@ -12,4 +12,4 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
-RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none"
diff --git a/deployment/Dockerfile.docker.armhf b/deployment/Dockerfile.docker.armhf
index 2a500246b..d99fa2a85 100644
--- a/deployment/Dockerfile.docker.armhf
+++ b/deployment/Dockerfile.docker.armhf
@@ -12,4 +12,4 @@ ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
# because of changes in docker and systemd we need to not build in parallel at the moment
# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting
-RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
+RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="${ARTIFACT_DIR}" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none"
diff --git a/deployment/build.linux.amd64 b/deployment/build.linux.amd64
index a7fb0544a..d0a5c1747 100755
--- a/deployment/build.linux.amd64
+++ b/deployment/build.linux.amd64
@@ -16,7 +16,7 @@ else
fi
# Build archives
-dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-x64 --output dist/jellyfin-server_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime linux-x64 --output dist/jellyfin-server_${version}/ "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none;UseAppHost=true"
tar -czf jellyfin-server_${version}_linux-amd64.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}
diff --git a/deployment/build.macos b/deployment/build.macos
index d808141ac..8bb8b2ebd 100755
--- a/deployment/build.macos
+++ b/deployment/build.macos
@@ -16,7 +16,7 @@ else
fi
# Build archives
-dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime osx-x64 --output dist/jellyfin-server_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime osx-x64 --output dist/jellyfin-server_${version}/ "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none;UseAppHost=true"
tar -czf jellyfin-server_${version}_macos-amd64.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}
diff --git a/deployment/build.portable b/deployment/build.portable
index 24a8cbf32..4c81d5672 100755
--- a/deployment/build.portable
+++ b/deployment/build.portable
@@ -16,7 +16,7 @@ else
fi
# Build archives
-dotnet publish Jellyfin.Server --configuration Release --output dist/jellyfin-server_${version}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+dotnet publish Jellyfin.Server --configuration Release --output dist/jellyfin-server_${version}/ "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none;UseAppHost=true"
tar -czf jellyfin-server_${version}_portable.tar.gz -C dist jellyfin-server_${version}
rm -rf dist/jellyfin-server_${version}
diff --git a/deployment/build.windows.amd64 b/deployment/build.windows.amd64
index bd5dc6438..47cfa2cd6 100755
--- a/deployment/build.windows.amd64
+++ b/deployment/build.windows.amd64
@@ -23,7 +23,7 @@ fi
output_dir="dist/jellyfin-server_${version}"
# Build binary
-dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime win-x64 --output ${output_dir}/ "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none;UseAppHost=true"
+dotnet publish Jellyfin.Server --configuration Release --self-contained --runtime win-x64 --output ${output_dir}/ "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none;UseAppHost=true"
# Prepare addins
addin_build_dir="$( mktemp -d )"
diff --git a/fedora/jellyfin.spec b/fedora/jellyfin.spec
index a1e0b5f14..291017d94 100644
--- a/fedora/jellyfin.spec
+++ b/fedora/jellyfin.spec
@@ -54,7 +54,7 @@ The Jellyfin media server backend.
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
dotnet publish --configuration Release --output='%{buildroot}%{_libdir}/jellyfin' --self-contained --runtime %{dotnet_runtime} \
- "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none" Jellyfin.Server
+ "-p:GenerateDocumentationFile=true;DebugSymbols=false;DebugType=none" Jellyfin.Server
%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/jellyfin/LICENSE
%{__install} -D -m 0644 %{SOURCE15} %{buildroot}%{_sysconfdir}/systemd/system/jellyfin.service.d/override.conf
%{__install} -D -m 0644 Jellyfin.Server/Resources/Configuration/logging.json %{buildroot}%{_sysconfdir}/jellyfin/logging.json
diff --git a/windows/build-jellyfin.ps1 b/windows/build-jellyfin.ps1
index b76a8e0bb..b65e619ee 100644
--- a/windows/build-jellyfin.ps1
+++ b/windows/build-jellyfin.ps1
@@ -40,7 +40,7 @@ function Build-JellyFin {
Write-Verbose "windowsversion-Architecture: $windowsversion-$Architecture"
Write-Verbose "InstallLocation: $ResolvedInstallLocation"
Write-Verbose "DotNetVerbosity: $DotNetVerbosity"
- dotnet publish --self-contained -c $BuildType --output $ResolvedInstallLocation -v $DotNetVerbosity -p:GenerateDocumentationFile=false -p:DebugSymbols=false -p:DebugType=none --runtime `"$windowsversion-$Architecture`" Jellyfin.Server
+ dotnet publish --self-contained -c $BuildType --output $ResolvedInstallLocation -v $DotNetVerbosity -p:GenerateDocumentationFile=true -p:DebugSymbols=false -p:DebugType=none --runtime `"$windowsversion-$Architecture`" Jellyfin.Server
}
function Install-FFMPEG {