mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-06 15:58:29 +01:00
Merge branch 'master' into userdb-efcore
# Conflicts: # Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs # Emby.Server.Implementations/ApplicationHost.cs # Emby.Server.Implementations/Devices/DeviceManager.cs # Jellyfin.Server/Jellyfin.Server.csproj # Jellyfin.Server/Migrations/MigrationRunner.cs # MediaBrowser.Controller/Devices/IDeviceManager.cs
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Model.Devices;
|
||||
using MediaBrowser.Model.Events;
|
||||
@@ -11,11 +9,6 @@ namespace MediaBrowser.Controller.Devices
|
||||
{
|
||||
public interface IDeviceManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when [camera image uploaded].
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<CameraImageUploadInfo>> CameraImageUploaded;
|
||||
|
||||
/// <summary>
|
||||
/// Saves the capabilities.
|
||||
/// </summary>
|
||||
@@ -45,22 +38,6 @@ namespace MediaBrowser.Controller.Devices
|
||||
/// <returns>IEnumerable<DeviceInfo>.</returns>
|
||||
QueryResult<DeviceInfo> GetDevices(DeviceQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the upload history.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>ContentUploadHistory.</returns>
|
||||
ContentUploadHistory GetCameraUploadHistory(string deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Accepts the upload.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <param name="stream">The stream.</param>
|
||||
/// <param name="file">The file.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task AcceptCameraUpload(string deviceId, Stream stream, LocalFileInfo file);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance [can access device] the specified user identifier.
|
||||
/// </summary>
|
||||
|
||||
@@ -39,10 +39,9 @@ namespace MediaBrowser.Controller
|
||||
int HttpsPort { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [supports HTTPS].
|
||||
/// Gets a value indicating whether the server should listen on an HTTPS port.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [supports HTTPS]; otherwise, <c>false</c>.</value>
|
||||
bool EnableHttps { get; }
|
||||
bool ListenWithHttps { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance has update available.
|
||||
@@ -57,34 +56,50 @@ namespace MediaBrowser.Controller
|
||||
string FriendlyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local ip address.
|
||||
/// Gets all the local IP addresses of this API instance. Each address is validated by sending a 'ping' request
|
||||
/// to the API that should exist at the address.
|
||||
/// </summary>
|
||||
/// <value>The local ip address.</value>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the task.</param>
|
||||
/// <returns>A list containing all the local IP addresses of the server.</returns>
|
||||
Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local API URL.
|
||||
/// Gets a local (LAN) URL that can be used to access the API. The hostname used is the first valid configured
|
||||
/// IP address that can be found via <see cref="GetLocalIpAddresses"/>. HTTPS will be preferred when available.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Token to cancel the request if needed.</param>
|
||||
/// <param name="forceHttp">Whether to force usage of plain HTTP protocol.</param>
|
||||
/// <value>The local API URL.</value>
|
||||
Task<string> GetLocalApiUrl(CancellationToken cancellationToken, bool forceHttp = false);
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the task.</param>
|
||||
/// <returns>The server URL.</returns>
|
||||
Task<string> GetLocalApiUrl(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local API URL.
|
||||
/// Gets a localhost URL that can be used to access the API using the loop-back IP address (127.0.0.1)
|
||||
/// over HTTP (not HTTPS).
|
||||
/// </summary>
|
||||
/// <param name="hostname">The hostname.</param>
|
||||
/// <param name="forceHttp">Whether to force usage of plain HTTP protocol.</param>
|
||||
/// <returns>The local API URL.</returns>
|
||||
string GetLocalApiUrl(ReadOnlySpan<char> hostname, bool forceHttp = false);
|
||||
/// <returns>The API URL.</returns>
|
||||
string GetLoopbackHttpApiUrl();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local API URL.
|
||||
/// Gets a local (LAN) URL that can be used to access the API. HTTPS will be preferred when available.
|
||||
/// </summary>
|
||||
/// <param name="address">The IP address.</param>
|
||||
/// <param name="forceHttp">Whether to force usage of plain HTTP protocol.</param>
|
||||
/// <returns>The local API URL.</returns>
|
||||
string GetLocalApiUrl(IPAddress address, bool forceHttp = false);
|
||||
/// <param name="address">The IP address to use as the hostname in the URL.</param>
|
||||
/// <returns>The API URL.</returns>
|
||||
string GetLocalApiUrl(IPAddress address);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a local (LAN) URL that can be used to access the API.
|
||||
/// Note: if passing non-null scheme or port it is up to the caller to ensure they form the correct pair.
|
||||
/// </summary>
|
||||
/// <param name="hostname">The hostname to use in the URL.</param>
|
||||
/// <param name="scheme">
|
||||
/// The scheme to use for the URL. If null, the scheme will be selected automatically,
|
||||
/// preferring HTTPS, if available.
|
||||
/// </param>
|
||||
/// <param name="port">
|
||||
/// The port to use for the URL. If null, the port will be selected automatically,
|
||||
/// preferring the HTTPS port, if available.
|
||||
/// </param>
|
||||
/// <returns>The API URL.</returns>
|
||||
string GetLocalApiUrl(ReadOnlySpan<char> hostname, string scheme = null, int? port = null);
|
||||
|
||||
/// <summary>
|
||||
/// Open a URL in an external browser window.
|
||||
@@ -101,7 +116,5 @@ namespace MediaBrowser.Controller
|
||||
string ReverseVirtualPath(string path);
|
||||
|
||||
Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next);
|
||||
|
||||
Task ExecuteWebsocketHandlerAsync(HttpContext context, Func<Task> next);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +77,6 @@ namespace MediaBrowser.Controller.Net
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
/// <summary>
|
||||
/// Starts sending messages over a web socket
|
||||
/// </summary>
|
||||
@@ -87,12 +85,12 @@ namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
var vals = message.Data.Split(',');
|
||||
|
||||
var dueTimeMs = long.Parse(vals[0], UsCulture);
|
||||
var periodMs = long.Parse(vals[1], UsCulture);
|
||||
var dueTimeMs = long.Parse(vals[0], CultureInfo.InvariantCulture);
|
||||
var periodMs = long.Parse(vals[1], CultureInfo.InvariantCulture);
|
||||
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
Logger.LogDebug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name);
|
||||
Logger.LogDebug("WS {1} begin transmitting to {0}", message.Connection.RemoteEndPoint, GetType().Name);
|
||||
|
||||
var state = new TStateType
|
||||
{
|
||||
@@ -154,7 +152,6 @@ namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
MessageType = Name,
|
||||
Data = data
|
||||
|
||||
}, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
state.DateLastSendUtc = DateTime.UtcNow;
|
||||
@@ -197,7 +194,7 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <param name="connection">The connection.</param>
|
||||
private void DisposeConnection(Tuple<IWebSocketConnection, CancellationTokenSource, TStateType> connection)
|
||||
{
|
||||
Logger.LogDebug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
|
||||
Logger.LogDebug("WS {1} stop transmitting to {0}", connection.Item1.RemoteEndPoint, GetType().Name);
|
||||
|
||||
// TODO disposing the connection seems to break websockets in subtle ways, so what is the purpose of this function really...
|
||||
// connection.Item1.Dispose();
|
||||
@@ -242,6 +239,7 @@ namespace MediaBrowser.Controller.Net
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Events;
|
||||
using MediaBrowser.Model.Services;
|
||||
@@ -9,9 +8,9 @@ using Microsoft.AspNetCore.Http;
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IHttpServer
|
||||
/// Interface IHttpServer.
|
||||
/// </summary>
|
||||
public interface IHttpServer : IDisposable
|
||||
public interface IHttpServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the URL prefix.
|
||||
@@ -19,11 +18,6 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <value>The URL prefix.</value>
|
||||
string[] UrlPrefixes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Stops this instance.
|
||||
/// </summary>
|
||||
void Stop();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [web socket connected].
|
||||
/// </summary>
|
||||
@@ -39,23 +33,18 @@ namespace MediaBrowser.Controller.Net
|
||||
/// </summary>
|
||||
string GlobalResponse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sends the http context to the socket listener
|
||||
/// </summary>
|
||||
/// <param name="ctx"></param>
|
||||
/// <returns></returns>
|
||||
Task ProcessWebSocketRequest(HttpContext ctx);
|
||||
|
||||
/// <summary>
|
||||
/// The HTTP request handler
|
||||
/// </summary>
|
||||
/// <param name="httpReq"></param>
|
||||
/// <param name="urlString"></param>
|
||||
/// <param name="host"></param>
|
||||
/// <param name="localPath"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
Task RequestHandler(IHttpRequest httpReq, string urlString, string host, string localPath,
|
||||
CancellationToken cancellationToken);
|
||||
Task RequestHandler(HttpContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Get the default CORS headers
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
IDictionary<string, string> GetDefaultCorsHeaders(IRequest req);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -7,18 +10,12 @@ using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public interface IWebSocketConnection : IDisposable
|
||||
public interface IWebSocketConnection
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when [closed].
|
||||
/// </summary>
|
||||
event EventHandler<EventArgs> Closed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id.
|
||||
/// </summary>
|
||||
/// <value>The id.</value>
|
||||
Guid Id { get; }
|
||||
event EventHandler<EventArgs>? Closed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last activity date.
|
||||
@@ -26,22 +23,17 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <value>The last activity date.</value>
|
||||
DateTime LastActivityDate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL.
|
||||
/// </summary>
|
||||
/// <value>The URL.</value>
|
||||
string Url { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the query string.
|
||||
/// </summary>
|
||||
/// <value>The query string.</value>
|
||||
IQueryCollection QueryString { get; set; }
|
||||
IQueryCollection QueryString { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the receive action.
|
||||
/// </summary>
|
||||
/// <value>The receive action.</value>
|
||||
Func<WebSocketMessageInfo, Task> OnReceive { get; set; }
|
||||
Func<WebSocketMessageInfo, Task>? OnReceive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the state.
|
||||
@@ -53,7 +45,7 @@ namespace MediaBrowser.Controller.Net
|
||||
/// Gets the remote end point.
|
||||
/// </summary>
|
||||
/// <value>The remote end point.</value>
|
||||
string RemoteEndPoint { get; }
|
||||
IPAddress? RemoteEndPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message asynchronously.
|
||||
@@ -65,21 +57,6 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <exception cref="ArgumentNullException">message</exception>
|
||||
Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendAsync(byte[] buffer, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">buffer</exception>
|
||||
Task SendAsync(string text, CancellationToken cancellationToken);
|
||||
Task ProcessAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -20,6 +21,6 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <summary>
|
||||
/// Sends the message.
|
||||
/// </summary>
|
||||
Task SendMessage<T>(string name, string messageId, T data, ISessionController[] allControllers, CancellationToken cancellationToken);
|
||||
Task SendMessage<T>(string name, Guid messageId, T data, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,23 @@ using Microsoft.Extensions.Logging;
|
||||
namespace MediaBrowser.Controller.Session
|
||||
{
|
||||
/// <summary>
|
||||
/// Class SessionInfo
|
||||
/// Class SessionInfo.
|
||||
/// </summary>
|
||||
public class SessionInfo : IDisposable
|
||||
public sealed class SessionInfo : IDisposable
|
||||
{
|
||||
private ISessionManager _sessionManager;
|
||||
// 1 second
|
||||
private const long ProgressIncrement = 10000000;
|
||||
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
|
||||
private readonly object _progressLock = new object();
|
||||
private Timer _progressTimer;
|
||||
private PlaybackProgressInfo _lastProgressInfo;
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
public SessionInfo(ISessionManager sessionManager, ILogger logger)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
@@ -97,8 +107,6 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <value>The name of the device.</value>
|
||||
public string DeviceName { get; set; }
|
||||
|
||||
public string DeviceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the now playing item.
|
||||
/// </summary>
|
||||
@@ -128,22 +136,6 @@ namespace MediaBrowser.Controller.Session
|
||||
[JsonIgnore]
|
||||
public ISessionController[] SessionControllers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the supported commands.
|
||||
/// </summary>
|
||||
/// <value>The supported commands.</value>
|
||||
public string[] SupportedCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Capabilities == null)
|
||||
{
|
||||
return new string[] { };
|
||||
}
|
||||
return Capabilities.SupportedCommands;
|
||||
}
|
||||
}
|
||||
|
||||
public TranscodingInfo TranscodingInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -215,6 +207,14 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
public QueueItem[] NowPlayingQueue { get; set; }
|
||||
|
||||
public bool HasCustomDeviceName { get; set; }
|
||||
|
||||
public string PlaylistItemId { get; set; }
|
||||
|
||||
public string UserPrimaryImageTag { get; set; }
|
||||
|
||||
public Tuple<ISessionController, bool> EnsureController<T>(Func<SessionInfo, ISessionController> factory)
|
||||
{
|
||||
var controllers = SessionControllers.ToList();
|
||||
@@ -258,10 +258,6 @@ namespace MediaBrowser.Controller.Session
|
||||
return false;
|
||||
}
|
||||
|
||||
private readonly object _progressLock = new object();
|
||||
private Timer _progressTimer;
|
||||
private PlaybackProgressInfo _lastProgressInfo;
|
||||
|
||||
public void StartAutomaticProgress(PlaybackProgressInfo progressInfo)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -284,9 +280,6 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
// 1 second
|
||||
private const long ProgressIncrement = 10000000;
|
||||
|
||||
private async void OnProgressTimerCallback(object state)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -345,8 +338,7 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
_disposed = true;
|
||||
@@ -358,30 +350,12 @@ namespace MediaBrowser.Controller.Session
|
||||
|
||||
foreach (var controller in controllers)
|
||||
{
|
||||
var disposable = controller as IDisposable;
|
||||
|
||||
if (disposable != null)
|
||||
if (controller is IDisposable disposable)
|
||||
{
|
||||
_logger.LogDebug("Disposing session controller {0}", disposable.GetType().Name);
|
||||
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error disposing session controller");
|
||||
}
|
||||
disposable.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_sessionManager = null;
|
||||
}
|
||||
|
||||
public QueueItem[] NowPlayingQueue { get; set; }
|
||||
public bool HasCustomDeviceName { get; set; }
|
||||
public string PlaylistItemId { get; set; }
|
||||
public string ServerId { get; set; }
|
||||
public string UserPrimaryImageTag { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user