mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-04-24 14:08:44 -04:00
Merge branch 'dev' into reformat
This commit is contained in:
commit
d116efe1f7
13 changed files with 137 additions and 152 deletions
|
@ -27,5 +27,9 @@ COPY --from=ffmpeg /ffmpeg-bin/* /usr/bin/
|
|||
EXPOSE 8096
|
||||
VOLUME /config /media
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libfontconfig1 --no-install-recommends # needed for Skia
|
||||
&& apt-get install --no-install-recommends --no-install-suggests -y \
|
||||
libfontconfig1 # Required for Skia \
|
||||
&& apt-get clean autoclean \
|
||||
&& apt-get autoremove \
|
||||
&& rm -rf /var/lib/{apt,dpkg,cache,log}
|
||||
ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config
|
||||
|
|
|
@ -13,4 +13,11 @@
|
|||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Authors>Jellyfin Contributors</Authors>
|
||||
<PackageId>Jellyfin.Naming</PackageId>
|
||||
<PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl>
|
||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -230,7 +230,6 @@ namespace Emby.Server.Implementations
|
|||
{
|
||||
get
|
||||
{
|
||||
|
||||
#if BETA
|
||||
return PackageVersionClass.Beta;
|
||||
#endif
|
||||
|
@ -510,7 +509,7 @@ namespace Emby.Server.Implementations
|
|||
protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
|
||||
where T : class
|
||||
{
|
||||
Container.RegisterSingleton(obj);
|
||||
Container.RegisterInstance<T>(obj);
|
||||
|
||||
if (manageLifetime)
|
||||
{
|
||||
|
@ -575,7 +574,7 @@ namespace Emby.Server.Implementations
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error loading assembly {file}", file);
|
||||
Logger.LogError(ex, "Error loading assembly {File}", file);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -387,7 +387,7 @@ namespace Emby.Server.Implementations.HttpClientManager
|
|||
{
|
||||
options.ResourcePool?.Release();
|
||||
|
||||
throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true };
|
||||
throw new HttpException($"Connection to {options.Url} timed out") { IsTimedOut = true };
|
||||
}
|
||||
|
||||
if (options.LogRequest)
|
||||
|
|
|
@ -54,39 +54,33 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
|
||||
private readonly List<IWebSocketConnection> _webSocketConnections = new List<IWebSocketConnection>();
|
||||
|
||||
public HttpListenerHost(IServerApplicationHost applicationHost,
|
||||
public HttpListenerHost(
|
||||
IServerApplicationHost applicationHost,
|
||||
ILogger logger,
|
||||
IServerConfigurationManager config,
|
||||
string defaultRedirectPath, INetworkManager networkManager, ITextEncoding textEncoding, IJsonSerializer jsonSerializer, IXmlSerializer xmlSerializer, Func<Type, Func<string, object>> funcParseFn)
|
||||
string defaultRedirectPath,
|
||||
INetworkManager networkManager,
|
||||
ITextEncoding textEncoding,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IXmlSerializer xmlSerializer,
|
||||
Func<Type, Func<string, object>> funcParseFn)
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
_appHost = applicationHost;
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
DefaultRedirectPath = defaultRedirectPath;
|
||||
_networkManager = networkManager;
|
||||
_textEncoding = textEncoding;
|
||||
_jsonSerializer = jsonSerializer;
|
||||
_xmlSerializer = xmlSerializer;
|
||||
_config = config;
|
||||
|
||||
_logger = logger;
|
||||
_funcParseFn = funcParseFn;
|
||||
|
||||
ResponseFilters = new Action<IRequest, IResponse, object>[] { };
|
||||
Instance = this;
|
||||
ResponseFilters = Array.Empty<Action<IRequest, IResponse, object>>();
|
||||
}
|
||||
|
||||
public string GlobalResponse { get; set; }
|
||||
|
||||
readonly Dictionary<Type, int> _mapExceptionToStatusCode = new Dictionary<Type, int>
|
||||
{
|
||||
{typeof (ResourceNotFoundException), 404},
|
||||
{typeof (RemoteServiceUnavailableException), 502},
|
||||
{typeof (FileNotFoundException), 404},
|
||||
//{typeof (DirectoryNotFoundException), 404},
|
||||
{typeof (SecurityException), 401},
|
||||
{typeof (ArgumentException), 400}
|
||||
};
|
||||
|
||||
protected ILogger Logger => _logger;
|
||||
|
||||
public object CreateInstance(Type type)
|
||||
|
@ -103,9 +97,9 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
{
|
||||
//Exec all RequestFilter attributes with Priority < 0
|
||||
var attributes = GetRequestFilterAttributes(requestDto.GetType());
|
||||
var i = 0;
|
||||
var count = attributes.Count;
|
||||
|
||||
int count = attributes.Count;
|
||||
int i = 0;
|
||||
for (; i < count && attributes[i].Priority < 0; i++)
|
||||
{
|
||||
var attribute = attributes[i];
|
||||
|
@ -167,10 +161,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
_webSocketConnections.Add(connection);
|
||||
}
|
||||
|
||||
if (WebSocketConnected != null)
|
||||
{
|
||||
WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection));
|
||||
}
|
||||
WebSocketConnected?.Invoke(this, new GenericEventArgs<IWebSocketConnection>(connection));
|
||||
}
|
||||
|
||||
private void Connection_Closed(object sender, EventArgs e)
|
||||
|
@ -205,26 +196,16 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
private int GetStatusCode(Exception ex)
|
||||
{
|
||||
if (ex is ArgumentException)
|
||||
switch (ex)
|
||||
{
|
||||
return 400;
|
||||
case ArgumentException _: return 400;
|
||||
case SecurityException _: return 401;
|
||||
case DirectoryNotFoundException _:
|
||||
case FileNotFoundException _:
|
||||
case ResourceNotFoundException _: return 404;
|
||||
case RemoteServiceUnavailableException _: return 502;
|
||||
default: return 500;
|
||||
}
|
||||
|
||||
var exceptionType = ex.GetType();
|
||||
|
||||
if (!_mapExceptionToStatusCode.TryGetValue(exceptionType, out var statusCode))
|
||||
{
|
||||
if (ex is DirectoryNotFoundException)
|
||||
{
|
||||
statusCode = 404;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusCode = 500;
|
||||
}
|
||||
}
|
||||
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
private async Task ErrorHandler(Exception ex, IRequest httpReq, bool logExceptionStackTrace, bool logExceptionMessage)
|
||||
|
@ -310,29 +291,22 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, int> _skipLogExtensions = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
|
||||
private static readonly string[] _skipLogExtensions =
|
||||
{
|
||||
{".js", 0},
|
||||
{".css", 0},
|
||||
{".woff", 0},
|
||||
{".woff2", 0},
|
||||
{".ttf", 0},
|
||||
{".html", 0}
|
||||
".js",
|
||||
".css",
|
||||
".woff",
|
||||
".woff2",
|
||||
".ttf",
|
||||
".html"
|
||||
};
|
||||
|
||||
private bool EnableLogging(string url, string localPath)
|
||||
{
|
||||
var extension = GetExtension(url);
|
||||
|
||||
if (string.IsNullOrEmpty(extension) || !_skipLogExtensions.ContainsKey(extension))
|
||||
{
|
||||
if (string.IsNullOrEmpty(localPath) || localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return ((string.IsNullOrEmpty(extension) || !_skipLogExtensions.Contains(extension))
|
||||
&& (string.IsNullOrEmpty(localPath) || localPath.IndexOf("system/ping", StringComparison.OrdinalIgnoreCase) == -1));
|
||||
}
|
||||
|
||||
private static string GetExtension(string url)
|
||||
|
@ -555,9 +529,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(localPath, "/mediabrowser/", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(localPath, "/mediabrowser", StringComparison.OrdinalIgnoreCase) ||
|
||||
localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (localPath.IndexOf("mediabrowser/web", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
httpRes.StatusCode = 200;
|
||||
httpRes.ContentType = "text/html";
|
||||
|
@ -711,7 +683,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
};
|
||||
}
|
||||
|
||||
_logger.LogError("Could not find handler for {pathInfo}", pathInfo);
|
||||
_logger.LogError("Could not find handler for {PathInfo}", pathInfo);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -725,13 +697,13 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
private void RedirectToSecureUrl(IHttpRequest httpReq, IResponse httpRes, string url)
|
||||
{
|
||||
int currentPort;
|
||||
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
|
||||
if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
|
||||
{
|
||||
currentPort = uri.Port;
|
||||
var builder = new UriBuilder(uri);
|
||||
builder.Port = _config.Configuration.PublicHttpsPort;
|
||||
builder.Scheme = "https";
|
||||
var builder = new UriBuilder(uri)
|
||||
{
|
||||
Port = _config.Configuration.PublicHttpsPort,
|
||||
Scheme = "https"
|
||||
};
|
||||
url = builder.Uri.ToString();
|
||||
|
||||
RedirectToUrl(httpRes, url);
|
||||
|
@ -831,12 +803,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
public Task<object> DeserializeJson(Type type, Stream stream)
|
||||
{
|
||||
//using (var reader = new StreamReader(stream))
|
||||
//{
|
||||
// var json = reader.ReadToEnd();
|
||||
// logger.LogInformation(json);
|
||||
// return _jsonSerializer.DeserializeFromString(json, type);
|
||||
//}
|
||||
return _jsonSerializer.DeserializeFromStreamAsync(stream, type);
|
||||
}
|
||||
|
||||
|
|
|
@ -410,8 +410,10 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
serializer.WriteObject(xw, from);
|
||||
xw.Flush();
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
var reader = new StreamReader(ms);
|
||||
return reader.ReadToEnd();
|
||||
using (var reader = new StreamReader(ms))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +425,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
{
|
||||
responseHeaders["ETag"] = string.Format("\"{0}\"", cacheKeyString);
|
||||
|
||||
var 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;
|
||||
|
||||
if (!noCache)
|
||||
{
|
||||
|
@ -461,8 +463,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
});
|
||||
}
|
||||
|
||||
public Task<object> GetStaticFileResult(IRequest requestContext,
|
||||
StaticFileResultOptions options)
|
||||
public Task<object> GetStaticFileResult(IRequest requestContext, StaticFileResultOptions options)
|
||||
{
|
||||
var path = options.Path;
|
||||
var fileShare = options.FileShare;
|
||||
|
@ -697,32 +698,26 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
|
||||
var ifModifiedSinceHeader = requestContext.Headers.Get("If-Modified-Since");
|
||||
|
||||
if (!string.IsNullOrEmpty(ifModifiedSinceHeader))
|
||||
if (!string.IsNullOrEmpty(ifModifiedSinceHeader)
|
||||
&& DateTime.TryParse(ifModifiedSinceHeader, out DateTime ifModifiedSince)
|
||||
&& IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified))
|
||||
{
|
||||
if (DateTime.TryParse(ifModifiedSinceHeader, out var ifModifiedSince))
|
||||
{
|
||||
if (IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match");
|
||||
|
||||
var hasCacheKey = !cacheKey.Equals(Guid.Empty);
|
||||
bool hasCacheKey = !cacheKey.Equals(Guid.Empty);
|
||||
|
||||
// Validate If-None-Match
|
||||
if ((hasCacheKey || !string.IsNullOrEmpty(ifNoneMatchHeader)))
|
||||
if ((hasCacheKey && !string.IsNullOrEmpty(ifNoneMatchHeader)))
|
||||
{
|
||||
ifNoneMatchHeader = (ifNoneMatchHeader ?? string.Empty).Trim('\"');
|
||||
|
||||
if (Guid.TryParse(ifNoneMatchHeader, out var ifNoneMatch))
|
||||
if (Guid.TryParse(ifNoneMatchHeader, out Guid ifNoneMatch)
|
||||
&& cacheKey.Equals(ifNoneMatch))
|
||||
{
|
||||
if (hasCacheKey && cacheKey.Equals(ifNoneMatch))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
/// </summary>
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
public List<Cookie> Cookies { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Additional HTTP Headers
|
||||
/// </summary>
|
||||
|
@ -72,7 +70,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
Headers["Accept-Ranges"] = "bytes";
|
||||
StatusCode = HttpStatusCode.PartialContent;
|
||||
|
||||
Cookies = new List<Cookie>();
|
||||
SetRangeValues(contentLength);
|
||||
}
|
||||
|
||||
|
@ -220,7 +217,5 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
get => (HttpStatusCode)Status;
|
||||
set => Status = (int)value;
|
||||
}
|
||||
|
||||
public string StatusDescription { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,14 +25,11 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
public void FilterResponse(IRequest req, IResponse res, object dto)
|
||||
{
|
||||
// Try to prevent compatibility view
|
||||
//res.AddHeader("X-UA-Compatible", "IE=Edge");
|
||||
res.AddHeader("Access-Control-Allow-Headers", "Accept, Accept-Language, Authorization, Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, Content-Type, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, X-Emby-Authorization");
|
||||
res.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS");
|
||||
res.AddHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
var exception = dto as Exception;
|
||||
|
||||
if (exception != null)
|
||||
if (dto is Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Error processing request for {RawUrl}", req.RawUrl);
|
||||
|
||||
|
@ -45,42 +42,26 @@ namespace Emby.Server.Implementations.HttpServer
|
|||
}
|
||||
}
|
||||
|
||||
var hasHeaders = dto as IHasHeaders;
|
||||
|
||||
if (hasHeaders != null)
|
||||
if (dto is IHasHeaders hasHeaders)
|
||||
{
|
||||
if (!hasHeaders.Headers.ContainsKey("Server"))
|
||||
{
|
||||
hasHeaders.Headers["Server"] = "Microsoft-NetCore/2.0, UPnP/1.0 DLNADOC/1.50";
|
||||
//hasHeaders.Headers["Server"] = "Mono-HTTPAPI/1.1";
|
||||
}
|
||||
|
||||
// Content length has to be explicitly set on on HttpListenerResponse or it won't be happy
|
||||
|
||||
if (hasHeaders.Headers.TryGetValue("Content-Length", out string contentLength) && !string.IsNullOrEmpty(contentLength))
|
||||
if (hasHeaders.Headers.TryGetValue("Content-Length", out string contentLength)
|
||||
&& !string.IsNullOrEmpty(contentLength))
|
||||
{
|
||||
var length = long.Parse(contentLength, UsCulture);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
res.SetContentLength(length);
|
||||
|
||||
//var listenerResponse = res.OriginalResponse as HttpListenerResponse;
|
||||
|
||||
//if (listenerResponse != null)
|
||||
//{
|
||||
// // Disable chunked encoding. Technically this is only needed when using Content-Range, but
|
||||
// // anytime we know the content length there's no need for it
|
||||
// listenerResponse.SendChunked = false;
|
||||
// return;
|
||||
//}
|
||||
|
||||
res.SendChunked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//res.KeepAlive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -15,7 +15,6 @@ namespace Emby.Server.Implementations.Services
|
|||
public HttpResult(object response, string contentType, HttpStatusCode statusCode)
|
||||
{
|
||||
this.Headers = new Dictionary<string, string>();
|
||||
this.Cookies = new List<Cookie>();
|
||||
|
||||
this.Response = response;
|
||||
this.ContentType = contentType;
|
||||
|
@ -26,8 +25,6 @@ namespace Emby.Server.Implementations.Services
|
|||
|
||||
public IDictionary<string, string> Headers { get; private set; }
|
||||
|
||||
public List<Cookie> Cookies { get; private set; }
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
public HttpStatusCode StatusCode
|
||||
|
@ -40,15 +37,16 @@ namespace Emby.Server.Implementations.Services
|
|||
|
||||
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = RequestContext != null ? RequestContext.Response : null;
|
||||
var response = RequestContext == null ? null : RequestContext.Response;
|
||||
|
||||
var bytesResponse = this.Response as byte[];
|
||||
if (bytesResponse != null)
|
||||
if (this.Response is byte[] bytesResponse)
|
||||
{
|
||||
var contentLength = bytesResponse.Length;
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
response.SetContentLength(contentLength);
|
||||
}
|
||||
|
||||
if (contentLength > 0)
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Net;
|
|||
using System.Net.Security;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Drawing;
|
||||
using Emby.Drawing.Skia;
|
||||
|
@ -29,35 +30,58 @@ namespace Jellyfin.Server
|
|||
{
|
||||
public static class Program
|
||||
{
|
||||
private static readonly TaskCompletionSource<bool> ApplicationTaskCompletionSource = new TaskCompletionSource<bool>();
|
||||
private static ILoggerFactory _loggerFactory;
|
||||
private static readonly CancellationTokenSource _tokenSource = new CancellationTokenSource();
|
||||
private static readonly ILoggerFactory _loggerFactory = new SerilogLoggerFactory();
|
||||
private static ILogger _logger;
|
||||
private static bool _restartOnShutdown;
|
||||
|
||||
public static async Task<int> Main(string[] args)
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var options = new StartupOptions(args);
|
||||
var version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
StartupOptions options = new StartupOptions(args);
|
||||
Version version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
|
||||
if (options.ContainsOption("-v") || options.ContainsOption("--version"))
|
||||
{
|
||||
Console.WriteLine(version.ToString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
var appPaths = createApplicationPaths(options);
|
||||
ServerApplicationPaths appPaths = createApplicationPaths(options);
|
||||
// $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
|
||||
Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);
|
||||
await createLogger(appPaths);
|
||||
_loggerFactory = new SerilogLoggerFactory();
|
||||
_logger = _loggerFactory.CreateLogger("Main");
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (sender, e)
|
||||
=> _logger.LogCritical((Exception)e.ExceptionObject, "Unhandled Exception");
|
||||
|
||||
// Intercept Ctrl+C and Ctrl+Break
|
||||
Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
if (_tokenSource.IsCancellationRequested)
|
||||
{
|
||||
return; // Already shutting down
|
||||
}
|
||||
e.Cancel = true;
|
||||
_logger.LogInformation("Ctrl+C, shutting down");
|
||||
Environment.ExitCode = 128 + 2;
|
||||
Shutdown();
|
||||
};
|
||||
|
||||
// Register a SIGTERM handler
|
||||
AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
|
||||
{
|
||||
if (_tokenSource.IsCancellationRequested)
|
||||
{
|
||||
return; // Already shutting down
|
||||
}
|
||||
_logger.LogInformation("Received a SIGTERM signal, shutting down");
|
||||
Environment.ExitCode = 128 + 15;
|
||||
Shutdown();
|
||||
};
|
||||
|
||||
_logger.LogInformation("Jellyfin version: {Version}", version);
|
||||
|
||||
var environmentInfo = new EnvironmentInfo(getOperatingSystem());
|
||||
EnvironmentInfo environmentInfo = new EnvironmentInfo(getOperatingSystem());
|
||||
ApplicationHost.LogEnvironmentInfo(_logger, appPaths, environmentInfo);
|
||||
|
||||
SQLitePCL.Batteries_V2.Init();
|
||||
|
@ -86,8 +110,16 @@ namespace Jellyfin.Server
|
|||
await appHost.RunStartupTasks();
|
||||
|
||||
// TODO: read input for a stop command
|
||||
// Block main thread until shutdown
|
||||
await ApplicationTaskCompletionSource.Task;
|
||||
|
||||
try
|
||||
{
|
||||
// Block main thread until shutdown
|
||||
await Task.Delay(-1, _tokenSource.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Don't throw on cancellation
|
||||
}
|
||||
|
||||
_logger.LogInformation("Disposing app host");
|
||||
}
|
||||
|
@ -96,8 +128,6 @@ namespace Jellyfin.Server
|
|||
{
|
||||
StartNewInstance(options);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static ServerApplicationPaths createApplicationPaths(StartupOptions options)
|
||||
|
@ -173,7 +203,7 @@ namespace Jellyfin.Server
|
|||
if (!File.Exists(configPath))
|
||||
{
|
||||
// For some reason the csproj name is used instead of the assembly name
|
||||
using (var rscstr = typeof(Program).Assembly
|
||||
using (Stream rscstr = typeof(Program).Assembly
|
||||
.GetManifestResourceStream("Jellyfin.Server.Resources.Configuration.logging.json"))
|
||||
using (Stream fstr = File.Open(configPath, FileMode.CreateNew))
|
||||
{
|
||||
|
@ -259,7 +289,10 @@ namespace Jellyfin.Server
|
|||
|
||||
public static void Shutdown()
|
||||
{
|
||||
ApplicationTaskCompletionSource.SetResult(true);
|
||||
if (!_tokenSource.IsCancellationRequested)
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Restart()
|
||||
|
|
|
@ -61,8 +61,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
}
|
||||
}
|
||||
|
||||
width /= Height.Value;
|
||||
return width;
|
||||
return width / height;
|
||||
}
|
||||
|
||||
return base.GetDefaultPrimaryImageAspectRatio();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("10.0.1")]
|
||||
[assembly: AssemblyFileVersion("10.0.1")]
|
||||
[assembly: AssemblyVersion("10.0.2")]
|
||||
[assembly: AssemblyFileVersion("10.0.2")]
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
jellyfin (10.0.2-1) unstable; urgency=medium
|
||||
|
||||
* Hotfix release
|
||||
* jellyfin/jellyfin-web#23: Update Chromecast app ID [via direct commit]
|
||||
* #540: Update Emby API keys to our own
|
||||
* #541: Change ItemId to Guid in ProviderManager
|
||||
* #566: Avoid printing stacktrace when bind to port 1900 fails
|
||||
|
||||
jellyfin (10.0.1-1) unstable; urgency=medium
|
||||
|
||||
* Hotfix release, corrects several small bugs from 10.0.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue